From e05c2f80da3bf538c045d0682426a25b1c4b862b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 Mar 2015 10:46:45 +0100 Subject: [PATCH 01/28] trans: Add early-out when translating unreachable controlflow expressions. --- src/librustc_trans/trans/controlflow.rs | 45 ++++++++++++- src/test/debuginfo/unreachable-locals.rs | 85 +++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 85d0bc0319f30..9093f56d33acc 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -40,6 +40,10 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let fcx = cx.fcx; debug!("trans_stmt({})", s.repr(cx.tcx())); + if cx.unreachable.get() { + return cx; + } + if cx.sess().asm_comments() { add_span_comment(cx, s.span, &s.repr(cx.tcx())); } @@ -76,6 +80,11 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_stmt_semi"); + + if cx.unreachable.get() { + return cx; + } + let ty = expr_ty(cx, e); if cx.fcx.type_needs_drop(ty) { expr::trans_to_lvalue(cx, e, "stmt").bcx @@ -89,6 +98,11 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, mut dest: expr::Dest) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_block"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; let mut bcx = bcx; @@ -141,6 +155,11 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id, dest.to_string(bcx.ccx())); let _icx = push_ctxt("trans_if"); + + if bcx.unreachable.get() { + return bcx; + } + let mut bcx = bcx; let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool()); @@ -214,6 +233,11 @@ pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, body: &ast::Block) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_while"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; // bcx @@ -257,6 +281,11 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, body: &ast::Block) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_loop"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; // bcx @@ -296,12 +325,13 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, exit: uint) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_break_cont"); - let fcx = bcx.fcx; if bcx.unreachable.get() { return bcx; } + let fcx = bcx.fcx; + // Locate loop that we will break to let loop_id = match opt_label { None => fcx.top_loop_scope(), @@ -341,6 +371,11 @@ pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, retval_expr: Option<&ast::Expr>) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_ret"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; let mut bcx = bcx; let dest = match (fcx.llretslotptr.get(), retval_expr) { @@ -372,6 +407,10 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_value"); + if bcx.unreachable.get() { + return bcx; + } + let v_str = C_str_slice(ccx, fail_str); let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); let filename = token::intern_and_get_ident(&loc.file.name); @@ -399,6 +438,10 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_bounds_check"); + if bcx.unreachable.get() { + return bcx; + } + // Extract the file/line from the span let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); let filename = token::intern_and_get_ident(&loc.file.name); diff --git a/src/test/debuginfo/unreachable-locals.rs b/src/test/debuginfo/unreachable-locals.rs index 309848d6cedc9..63536b1383475 100644 --- a/src/test/debuginfo/unreachable-locals.rs +++ b/src/test/debuginfo/unreachable-locals.rs @@ -26,6 +26,22 @@ fn after_return() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_panic() { @@ -36,6 +52,22 @@ fn after_panic() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_diverging_function() { @@ -46,6 +78,22 @@ fn after_diverging_function() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_break() { @@ -57,18 +105,50 @@ fn after_break() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } } fn after_continue() { for _ in 0..10i32 { - break; + continue; let x = "0"; let (ref y,z) = (1i32, 2u32); match (20i32, 'c') { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } } @@ -83,3 +163,6 @@ fn main() { fn diverge() -> ! { panic!(); } + +fn some_predicate() -> bool { true || false } + From 45c10db41f2af5919621ff69f5dc090cc917c1d3 Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:08:53 -0400 Subject: [PATCH 02/28] Clarified and simplified algorithm for increasing size of buffer in read_to_end() --- src/libstd/io/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 830a88bb6c95b..3de9a06892627 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -101,15 +101,14 @@ fn append_to_string(buf: &mut String, f: F) -> Result fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let mut len = start_len; - let mut cap_bump = 16; + let min_cap_bump = 16; let ret; loop { if len == buf.len() { if buf.capacity() == buf.len() { - if cap_bump < DEFAULT_BUF_SIZE { - cap_bump *= 2; - } - buf.reserve(cap_bump); + // reserve() rounds up our request to the nearest power of two, so after the first + // time the capacity is exceeded, we double our capacity at each call to reserve. + buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); buf.extend(iter::repeat(0).take(new_area)); From 2982fe39ad93e29709a2e1414a4228718c8de28a Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:23:46 -0400 Subject: [PATCH 03/28] 80 character line limit --- src/libstd/io/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3de9a06892627..bc3791b99d07a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -106,8 +106,9 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result loop { if len == buf.len() { if buf.capacity() == buf.len() { - // reserve() rounds up our request to the nearest power of two, so after the first - // time the capacity is exceeded, we double our capacity at each call to reserve. + // reserve() rounds up our request to the nearest power of two, + // so after the first time the capacity is exceeded, we double + // our capacity at each call to reserve. buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); From 8d3e55908ae0e51f04c170133c9f9739886b8e2e Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:29:11 -0400 Subject: [PATCH 04/28] Clearer wording --- src/libstd/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index bc3791b99d07a..c4ec2a7ca17f9 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -106,9 +106,9 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result loop { if len == buf.len() { if buf.capacity() == buf.len() { - // reserve() rounds up our request to the nearest power of two, - // so after the first time the capacity is exceeded, we double - // our capacity at each call to reserve. + // reserve() rounds up our request such that every request + // (with maybe the exception of the first request) for the + // same amount of space doubles our capacity. buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); From 240734c31e529557583a0dc8e97abf858b4a375d Mon Sep 17 00:00:00 2001 From: bcoopers Date: Mon, 30 Mar 2015 13:59:32 -0400 Subject: [PATCH 05/28] Only zero at most 64k at a time. We still use the doubling reallocation strategy since extend() calls reserve() and/or push() for us. --- src/libstd/io/mod.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c4ec2a7ca17f9..6b03fb45c779d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -101,18 +101,14 @@ fn append_to_string(buf: &mut String, f: F) -> Result fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let mut len = start_len; - let min_cap_bump = 16; + let mut new_write_size = 16; let ret; loop { if len == buf.len() { - if buf.capacity() == buf.len() { - // reserve() rounds up our request such that every request - // (with maybe the exception of the first request) for the - // same amount of space doubles our capacity. - buf.reserve(min_cap_bump); + if new_write_size < DEFAULT_BUF_SIZE { + new_write_size *= 2; } - let new_area = buf.capacity() - buf.len(); - buf.extend(iter::repeat(0).take(new_area)); + buf.extend(iter::repeat(0).take(new_write_size)); } match r.read(&mut buf[len..]) { From 0939837867e77f478dcd3735f3a6ce8823f5fd48 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 9 Mar 2015 16:39:50 -0400 Subject: [PATCH 06/28] Rename the cryptic cres and ures types. --- src/librustc/middle/infer/bivariate.rs | 14 +-- src/librustc/middle/infer/combine.rs | 88 +++++++++++------- src/librustc/middle/infer/equate.rs | 12 +-- src/librustc/middle/infer/glb.rs | 12 +-- .../middle/infer/higher_ranked/mod.rs | 14 +-- src/librustc/middle/infer/lattice.rs | 8 +- src/librustc/middle/infer/lub.rs | 12 +-- src/librustc/middle/infer/mod.rs | 93 +++++-------------- .../middle/infer/region_inference/mod.rs | 16 ++-- src/librustc/middle/infer/sub.rs | 12 +-- src/librustc/middle/infer/unify.rs | 14 +-- src/librustc_typeck/check/coercion.rs | 6 +- src/librustc_typeck/check/method/probe.rs | 2 +- 13 files changed, 138 insertions(+), 165 deletions(-) diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 17b0d788590c4..91e1fea7ca52e 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -29,7 +29,7 @@ use middle::ty::BuiltinBounds; use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::infer::combine::*; -use middle::infer::cres; +use middle::infer::CombineResult; use middle::infer::type_variable::BiTo; use util::ppaux::Repr; @@ -47,7 +47,7 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { match v { ty::Invariant => self.equate().tys(a, b), @@ -58,7 +58,7 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + -> CombineResult<'tcx, ty::Region> { match v { ty::Invariant => self.equate().regions(a, b), @@ -68,14 +68,14 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } } - fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&self, a: ty::Region, _: ty::Region) -> CombineResult<'tcx, ty::Region> { Ok(a) } fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> + -> CombineResult<'tcx, BuiltinBounds> { if a != b { Err(ty::terr_builtin_bounds(expected_found(self, a, b))) @@ -84,7 +84,7 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -114,7 +114,7 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx> { let a1 = ty::erase_late_bound_regions(self.tcx(), a); diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 9aa17b2b1d9fe..220a23b183a98 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -38,7 +38,7 @@ use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; -use super::{InferCtxt, cres}; +use super::{InferCtxt, CombineResult}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; @@ -74,7 +74,7 @@ pub trait Combine<'tcx> : Sized { fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) } fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) } - fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> { + fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> CombineResult<'tcx, ty::mt<'tcx>> { debug!("{}.mts({}, {})", self.tag(), a.repr(self.tcx()), @@ -94,20 +94,20 @@ pub trait Combine<'tcx> : Sized { } fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>>; + -> CombineResult<'tcx, Ty<'tcx>>; - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>; + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>>; fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region>; + -> CombineResult<'tcx, ty::Region>; - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>; + fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region>; fn substs(&self, item_def_id: ast::DefId, a_subst: &subst::Substs<'tcx>, b_subst: &subst::Substs<'tcx>) - -> cres<'tcx, subst::Substs<'tcx>> + -> CombineResult<'tcx, subst::Substs<'tcx>> { debug!("substs: item_def_id={} a_subst={} b_subst={}", item_def_id.repr(self.infcx().tcx), @@ -126,7 +126,7 @@ pub trait Combine<'tcx> : Sized { variances: Option<&ty::ItemVariances>, a_subst: &subst::Substs<'tcx>, b_subst: &subst::Substs<'tcx>) - -> cres<'tcx, subst::Substs<'tcx>> + -> CombineResult<'tcx, subst::Substs<'tcx>> { let mut substs = subst::Substs::empty(); @@ -163,7 +163,7 @@ pub trait Combine<'tcx> : Sized { variances: Option<&[ty::Variance]>, a_tys: &[Ty<'tcx>], b_tys: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> + -> CombineResult<'tcx, Vec>> { if a_tys.len() != b_tys.len() { return Err(ty::terr_ty_param_size(expected_found(this, @@ -183,7 +183,7 @@ pub trait Combine<'tcx> : Sized { variances: Option<&[ty::Variance]>, a_rs: &[ty::Region], b_rs: &[ty::Region]) - -> cres<'tcx, Vec> + -> CombineResult<'tcx, Vec> { let tcx = this.infcx().tcx; let num_region_params = a_rs.len(); @@ -212,7 +212,7 @@ pub trait Combine<'tcx> : Sized { } fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>, - b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> { + b: &ty::BareFnTy<'tcx>) -> CombineResult<'tcx, ty::BareFnTy<'tcx>> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let abi = try!(self.abi(a.abi, b.abi)); let sig = try!(self.binders(&a.sig, &b.sig)); @@ -221,7 +221,7 @@ pub trait Combine<'tcx> : Sized { sig: sig}) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> { + fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> CombineResult<'tcx, ty::FnSig<'tcx>> { if a.variadic != b.variadic { return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic))); } @@ -248,7 +248,7 @@ pub trait Combine<'tcx> : Sized { fn argvecs<'tcx, C>(combiner: &C, a_args: &[Ty<'tcx>], b_args: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> + -> CombineResult<'tcx, Vec>> where C: Combine<'tcx> { if a_args.len() == b_args.len() { a_args.iter().zip(b_args.iter()) @@ -259,11 +259,11 @@ pub trait Combine<'tcx> : Sized { } } - fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t)) } - fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> { + fn unsafeties(&self, a: Unsafety, b: Unsafety) -> CombineResult<'tcx, Unsafety> { if a != b { Err(ty::terr_unsafety_mismatch(expected_found(self, a, b))) } else { @@ -271,7 +271,7 @@ pub trait Combine<'tcx> : Sized { } } - fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> { + fn abi(&self, a: abi::Abi, b: abi::Abi) -> CombineResult<'tcx, abi::Abi> { if a == b { Ok(a) } else { @@ -282,7 +282,7 @@ pub trait Combine<'tcx> : Sized { fn projection_tys(&self, a: &ty::ProjectionTy<'tcx>, b: &ty::ProjectionTy<'tcx>) - -> cres<'tcx, ty::ProjectionTy<'tcx>> + -> CombineResult<'tcx, ty::ProjectionTy<'tcx>> { if a.item_name != b.item_name { Err(ty::terr_projection_name_mismatched( @@ -296,7 +296,7 @@ pub trait Combine<'tcx> : Sized { fn projection_predicates(&self, a: &ty::ProjectionPredicate<'tcx>, b: &ty::ProjectionPredicate<'tcx>) - -> cres<'tcx, ty::ProjectionPredicate<'tcx>> + -> CombineResult<'tcx, ty::ProjectionPredicate<'tcx>> { let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty)); let ty = try!(self.tys(a.ty, b.ty)); @@ -306,7 +306,7 @@ pub trait Combine<'tcx> : Sized { fn projection_bounds(&self, a: &Vec>, b: &Vec>) - -> cres<'tcx, Vec>> + -> CombineResult<'tcx, Vec>> { // To be compatible, `a` and `b` must be for precisely the // same set of traits and item names. We always require that @@ -326,7 +326,7 @@ pub trait Combine<'tcx> : Sized { fn existential_bounds(&self, a: &ty::ExistentialBounds<'tcx>, b: &ty::ExistentialBounds<'tcx>) - -> cres<'tcx, ty::ExistentialBounds<'tcx>> + -> CombineResult<'tcx, ty::ExistentialBounds<'tcx>> { let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound)); let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); @@ -339,7 +339,7 @@ pub trait Combine<'tcx> : Sized { fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> + -> CombineResult<'tcx, BuiltinBounds> { // Two sets of builtin bounds are only relatable if they are // precisely the same (but see the coercion code). @@ -353,7 +353,7 @@ pub trait Combine<'tcx> : Sized { fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> + -> CombineResult<'tcx, ty::TraitRef<'tcx>> { // Different traits cannot be related if a.def_id != b.def_id { @@ -364,14 +364,14 @@ pub trait Combine<'tcx> : Sized { } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx>; // this must be overridden to do correctly, so as to account for higher-ranked // behavior } pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { - fn combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; + fn combine>(combiner: &C, a: &Self, b: &Self) -> CombineResult<'tcx, Self>; } impl<'tcx,T> Combineable<'tcx> for Rc @@ -380,7 +380,7 @@ impl<'tcx,T> Combineable<'tcx> for Rc fn combine(combiner: &C, a: &Rc, b: &Rc) - -> cres<'tcx, Rc> + -> CombineResult<'tcx, Rc> where C: Combine<'tcx> { Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) } @@ -390,7 +390,7 @@ impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { fn combine(combiner: &C, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> + -> CombineResult<'tcx, ty::TraitRef<'tcx>> where C: Combine<'tcx> { combiner.trait_refs(a, b) } @@ -400,7 +400,7 @@ impl<'tcx> Combineable<'tcx> for Ty<'tcx> { fn combine(combiner: &C, a: &Ty<'tcx>, b: &Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> where C: Combine<'tcx> { combiner.tys(*a, *b) } @@ -410,7 +410,7 @@ impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> { fn combine(combiner: &C, a: &ty::ProjectionPredicate<'tcx>, b: &ty::ProjectionPredicate<'tcx>) - -> cres<'tcx, ty::ProjectionPredicate<'tcx>> + -> CombineResult<'tcx, ty::ProjectionPredicate<'tcx>> where C: Combine<'tcx> { combiner.projection_predicates(a, b) } @@ -420,7 +420,7 @@ impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> { fn combine(combiner: &C, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> + -> CombineResult<'tcx, ty::FnSig<'tcx>> where C: Combine<'tcx> { combiner.fn_sigs(a, b) } @@ -448,7 +448,7 @@ pub fn expected_found<'tcx, C, T>(this: &C, pub fn super_tys<'tcx, C>(this: &C, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> where C: Combine<'tcx> { let tcx = this.infcx().tcx; let a_sty = &a.sty; @@ -616,7 +616,7 @@ pub fn super_tys<'tcx, C>(this: &C, vid_is_expected: bool, vid: ty::IntVid, val: ty::IntVarValue) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> where C: Combine<'tcx> { try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); match val { @@ -629,7 +629,7 @@ pub fn super_tys<'tcx, C>(this: &C, vid_is_expected: bool, vid: ty::FloatVid, val: ast::FloatTy) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> where C: Combine<'tcx> { try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); Ok(ty::mk_mach_float(this.tcx(), val)) @@ -660,7 +660,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid) - -> cres<'tcx, ()> + -> CombineResult<'tcx, ()> { let tcx = self.infcx.tcx; let mut stack = Vec::new(); @@ -746,7 +746,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { ty: Ty<'tcx>, for_vid: ty::TyVid, make_region_vars: bool) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { let mut generalize = Generalizer { infcx: self.infcx, @@ -839,3 +839,23 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { self.infcx.next_region_var(MiscVariable(self.span)) } } + +pub trait CombineResultCompare<'tcx, T> { + fn compare(&self, t: T, f: F) -> CombineResult<'tcx, T> where + F: FnOnce() -> ty::type_err<'tcx>; +} + +impl<'tcx, T:Clone + PartialEq> CombineResultCompare<'tcx, T> for CombineResult<'tcx, T> { + fn compare(&self, t: T, f: F) -> CombineResult<'tcx, T> where + F: FnOnce() -> ty::type_err<'tcx>, + { + (*self).clone().and_then(|s| { + if s == t { + (*self).clone() + } else { + Err(f()) + } + }) + } +} + diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 59ed2dfd24f25..59394d1dd3715 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -11,7 +11,7 @@ use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::infer::combine::*; -use middle::infer::cres; +use middle::infer::CombineResult; use middle::infer::Subtype; use middle::infer::type_variable::EqTo; use util::ppaux::Repr; @@ -30,20 +30,20 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { // Once we're equating, it doesn't matter what the variance is. self.tys(a, b) } fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + -> CombineResult<'tcx, ty::Region> { // Once we're equating, it doesn't matter what the variance is. self.regions(a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), @@ -52,7 +52,7 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { Ok(a) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -82,7 +82,7 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx> { try!(self.sub().binders(a, b)); diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 3b83d37f58234..28c0b4df7f402 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -11,7 +11,7 @@ use super::combine::*; use super::lattice::*; use super::higher_ranked::HigherRankedRelations; -use super::cres; +use super::CombineResult; use super::Subtype; use middle::ty::{self, Ty}; @@ -32,7 +32,7 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { match v { ty::Invariant => self.equate().tys(a, b), @@ -43,7 +43,7 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { } fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + -> CombineResult<'tcx, ty::Region> { match v { ty::Invariant => self.equate().regions(a, b), @@ -53,7 +53,7 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { } } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), @@ -62,11 +62,11 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx> { self.higher_ranked_glb(a, b) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 16b387330b9ef..3754f52d0585d 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,7 +11,7 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::{CombinedSnapshot, CombineResult, InferCtxt, HigherRankedType, SkolemizationMap}; use super::combine::{Combine, Combineable}; use middle::subst; @@ -22,13 +22,13 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::Repr; pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> where T : Combineable<'tcx>; - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> where T : Combineable<'tcx>; - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> where T : Combineable<'tcx>; } @@ -44,7 +44,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { fn higher_ranked_sub(&self, a: &Binder, b: &Binder) - -> cres<'tcx, Binder> + -> CombineResult<'tcx, Binder> where T : Combineable<'tcx> { debug!("higher_ranked_sub(a={}, b={})", @@ -104,7 +104,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C }); } - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> where T : Combineable<'tcx> { // Start a snapshot so we can examine "all bindings that were @@ -194,7 +194,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> where T : Combineable<'tcx> { debug!("{}.higher_ranked_glb({}, {})", diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 9c764628c14f8..6cbf20f26aefd 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -41,11 +41,11 @@ use util::ppaux::Repr; pub trait LatticeDir<'tcx> { // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()>; + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()>; } impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()> { let sub = self.sub(); try!(sub.tys(a, v)); try!(sub.tys(b, v)); @@ -54,7 +54,7 @@ impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> { } impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()> { let sub = self.sub(); try!(sub.tys(v, a)); try!(sub.tys(v, b)); @@ -65,7 +65,7 @@ impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> { pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { debug!("{}.lattice_tys({}, {})", this.tag(), diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 5000ab32ff671..123b6cbcc0a6c 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -11,7 +11,7 @@ use super::combine::*; use super::higher_ranked::HigherRankedRelations; use super::lattice::*; -use super::cres; +use super::CombineResult; use super::Subtype; use middle::ty::{self, Ty}; @@ -32,7 +32,7 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { match v { ty::Invariant => self.equate().tys(a, b), @@ -43,7 +43,7 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { } fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + -> CombineResult<'tcx, ty::Region> { match v { ty::Invariant => self.equate().regions(a, b), @@ -53,7 +53,7 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { } } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.tcx()), @@ -62,11 +62,11 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx> { self.higher_ranked_lub(a, b) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4cc9b65c2dab3..bb94d95dc571f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -63,8 +63,8 @@ pub mod unify; pub type Bound = Option; -pub type cres<'tcx, T> = Result>; // "combine result" -pub type ures<'tcx> = cres<'tcx, ()>; // "unify result" +pub type CombineResult<'tcx, T> = Result>; // "combine result" +pub type UnitResult<'tcx> = CombineResult<'tcx, ()>; // "unify result" pub type fres = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { @@ -359,7 +359,7 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.commit_if_ok(|| { @@ -370,18 +370,18 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> { + -> UnitResult<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).tys(a, b).to_ures() + cx.sub(true, trace).tys(a, b).map(|_| ()) }) } -pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> +pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> UnitResult<'tcx> { cx.can_equate(&a, &b) } @@ -401,7 +401,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.commit_if_ok( @@ -413,7 +413,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); @@ -433,57 +433,6 @@ fn expected_found(a_is_expected: bool, } } -trait then<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>; -} - -impl<'tcx> then<'tcx> for ures<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>, - { - self.and_then(move |_| f()) - } -} - -trait ToUres<'tcx> { - fn to_ures(&self) -> ures<'tcx>; -} - -impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> { - fn to_ures(&self) -> ures<'tcx> { - match *self { - Ok(ref _v) => Ok(()), - Err(ref e) => Err((*e)) - } - } -} - -trait CresCompare<'tcx, T> { - fn compare(&self, t: T, f: F) -> cres<'tcx, T> where - F: FnOnce() -> ty::type_err<'tcx>; -} - -impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> { - fn compare(&self, t: T, f: F) -> cres<'tcx, T> where - F: FnOnce() -> ty::type_err<'tcx>, - { - (*self).clone().and_then(move |s| { - if s == t { - (*self).clone() - } else { - Err(f()) - } - }) - } -} - -pub fn uok<'tcx>() -> ures<'tcx> { - Ok(()) -} - #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot { type_snapshot: type_variable::Snapshot, @@ -691,12 +640,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); self.commit_if_ok(|| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.sub(a_is_expected, trace).tys(a, b).to_ures() + self.sub(a_is_expected, trace).tys(a, b).map(|_| ()) }) } @@ -705,11 +654,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { self.commit_if_ok(|| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.equate(a_is_expected, trace).tys(a, b).to_ures() + self.equate(a_is_expected, trace).tys(a, b).map(|_| ()) }) } @@ -718,7 +667,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Rc>, b: Rc>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_trait_refs({} <: {})", a.repr(self.tcx), @@ -728,7 +677,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures() + self.sub(a_is_expected, trace).trait_refs(&*a, &*b).map(|_| ()) }) } @@ -737,7 +686,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_poly_trait_refs({} <: {})", a.repr(self.tcx), @@ -747,7 +696,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).binders(&a, &b).to_ures() + self.sub(a_is_expected, trace).binders(&a, &b).map(|_| ()) }) } @@ -774,7 +723,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn leak_check(&self, skol_map: &SkolemizationMap, snapshot: &CombinedSnapshot) - -> ures<'tcx> + -> UnitResult<'tcx> { /*! See `higher_ranked::leak_check` */ @@ -799,7 +748,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn equality_predicate(&self, span: Span, predicate: &ty::PolyEquatePredicate<'tcx>) - -> ures<'tcx> { + -> UnitResult<'tcx> { self.try(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); @@ -812,7 +761,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn region_outlives_predicate(&self, span: Span, predicate: &ty::PolyRegionOutlivesPredicate) - -> ures<'tcx> { + -> UnitResult<'tcx> { self.try(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); @@ -1104,7 +1053,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bs); } - pub fn can_equate(&self, a: &T, b: &T) -> ures<'tcx> + pub fn can_equate(&self, a: &T, b: &T) -> UnitResult<'tcx> where T : Combineable<'tcx> + Repr<'tcx> { debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx)); @@ -1118,7 +1067,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { values: Types(expected_found(true, e, e)) }; let eq = self.equate(true, trace); Combineable::combine(&eq, a, b) - }).to_ures() + }).map(|_| ()) } } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index c432d114b6eed..e7c5d1111a216 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -18,7 +18,7 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use self::Classification::*; -use super::cres; +use super::CombineResult; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use middle::region; @@ -799,7 +799,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// regions are given as argument, in any order, a consistent result is returned. fn lub_free_regions(&self, a: &FreeRegion, - b: &FreeRegion) -> ty::Region + b: &FreeRegion) + -> ty::Region { return match a.cmp(b) { Less => helper(self, a, b), @@ -824,7 +825,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn glb_concrete_regions(&self, a: Region, b: Region) - -> cres<'tcx, Region> { + -> CombineResult<'tcx, Region> + { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { (ReLateBound(..), _) | @@ -898,7 +900,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// returned. fn glb_free_regions(&self, a: &FreeRegion, - b: &FreeRegion) -> cres<'tcx, ty::Region> + b: &FreeRegion) + -> CombineResult<'tcx, ty::Region> { return match a.cmp(b) { Less => helper(self, a, b), @@ -908,7 +911,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, a: &FreeRegion, - b: &FreeRegion) -> cres<'tcx, ty::Region> + b: &FreeRegion) -> CombineResult<'tcx, ty::Region> { if this.tcx.region_maps.sub_free_region(*a, *b) { Ok(ty::ReFree(*a)) @@ -926,7 +929,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { region_a: ty::Region, region_b: ty::Region, scope_a: region::CodeExtent, - scope_b: region::CodeExtent) -> cres<'tcx, Region> + scope_b: region::CodeExtent) + -> CombineResult<'tcx, Region> { // We want to generate the intersection of two // scopes or two free regions. So, if one of diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 5d23fe3f1348d..d58a911e86064 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -9,7 +9,7 @@ // except according to those terms. use super::combine::*; -use super::cres; +use super::CombineResult; use super::higher_ranked::HigherRankedRelations; use super::Subtype; use super::type_variable::{SubtypeOf, SupertypeOf}; @@ -33,7 +33,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + -> CombineResult<'tcx, Ty<'tcx>> { match v { ty::Invariant => self.equate().tys(a, b), @@ -44,7 +44,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + -> CombineResult<'tcx, ty::Region> { match v { ty::Invariant => self.equate().regions(a, b), @@ -54,7 +54,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.tcx()), @@ -63,7 +63,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { Ok(a) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); if a == b { return Ok(a); } @@ -99,7 +99,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> where T : Combineable<'tcx> { self.higher_ranked_sub(a, b) diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 8a736d47b5d89..de96e9b49feee 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -14,7 +14,7 @@ use std::marker; use middle::ty::{expected_found, IntVarValue}; use middle::ty::{self, Ty}; -use middle::infer::{uok, ures}; +use middle::infer::UnitResult; use middle::infer::InferCtxt; use std::cell::RefCell; use std::fmt::Debug; @@ -236,7 +236,7 @@ pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug { pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool, a_t: V, b_t: V) - -> ures<'tcx> { + -> UnitResult<'tcx> { if a_is_expected { Err(SimplyUnifiable::to_type_err( ty::expected_found {expected: a_t, found: b_t})) @@ -255,12 +255,12 @@ pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> a_is_expected: bool, a_id: K, b_id: K) - -> ures<'tcx>; + -> UnitResult<'tcx>; fn simple_var_t(&self, a_is_expected: bool, a_id: K, b: V) - -> ures<'tcx>; + -> UnitResult<'tcx>; fn probe_var(&self, a_id: K) -> Option>; } @@ -276,7 +276,7 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx a_is_expected: bool, a_id: K, b_id: K) - -> ures<'tcx> + -> UnitResult<'tcx> { let tcx = self.tcx; let table = UnifyKey::unification_table(self); @@ -285,7 +285,7 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx let a_id = node_a.key.clone(); let b_id = node_b.key.clone(); - if a_id == b_id { return uok(); } + if a_id == b_id { return Ok(()); } let combined = { match (&node_a.value, &node_b.value) { @@ -317,7 +317,7 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx a_is_expected: bool, a_id: K, b: V) - -> ures<'tcx> + -> UnitResult<'tcx> { let tcx = self.tcx; let table = UnifyKey::unification_table(self); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ae1dbbb1b00ad..d48927c61d2c7 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,7 +62,7 @@ use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use middle::infer::{self, cres, Coercion, TypeTrace}; +use middle::infer::{self, CombineResult, Coercion, TypeTrace}; use middle::infer::combine::Combine; use middle::infer::sub::Sub; use middle::subst; @@ -79,7 +79,7 @@ struct Coerce<'a, 'tcx: 'a> { trace: TypeTrace<'tcx> } -type CoerceResult<'tcx> = cres<'tcx, Option>>; +type CoerceResult<'tcx> = CombineResult<'tcx, Option>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -534,7 +534,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, ()> { + -> CombineResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); let adjustment = try!(indent(|| { fcx.infcx().commit_if_ok(|| { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6349ea57f2ff1..e203019bd0638 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1130,7 +1130,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::ures<'tcx> { + fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> { self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup) } From 4b0edb96d080fadccc542dad50e6576c8e11bd85 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 10 Mar 2015 07:02:27 -0400 Subject: [PATCH 07/28] Combine `try` and `commit_if_ok` and make some details of inference context private. --- .../middle/infer/higher_ranked/mod.rs | 6 +- src/librustc/middle/infer/mod.rs | 90 ++++++++----------- .../middle/infer/region_inference/mod.rs | 10 +-- src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/select.rs | 10 +-- src/librustc_typeck/check/coercion.rs | 40 +++++---- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/regionck.rs | 2 +- .../object-lifetime-default-elision.rs | 4 +- .../object-lifetime-default-from-box-error.rs | 4 +- ...ions-close-over-type-parameter-multiple.rs | 2 +- .../regions-trait-object-subtyping.rs | 2 +- 13 files changed, 81 insertions(+), 95 deletions(-) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 3754f52d0585d..9280ffd06545a 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -60,7 +60,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx().commit_if_ok(|snapshot| { // First, we instantiate each bound region in the subtype with a fresh // region variable. let (a_prime, _) = @@ -109,7 +109,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx().commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. let span = self.trace().origin.span(); let (a_with_fresh, a_map) = @@ -202,7 +202,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx().commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = self.infcx().replace_late_bound_regions_with_fresh_var( diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index bb94d95dc571f..31ce8503ed0ac 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -265,7 +265,7 @@ pub enum LateBoundRegionConversionTime { /// /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] -pub enum RegionVariableOrigin<'tcx> { +pub enum RegionVariableOrigin { // Region variables created for ill-categorized reasons, // mostly indicates places in need of refactoring MiscVariable(Span), @@ -280,7 +280,7 @@ pub enum RegionVariableOrigin<'tcx> { Autoref(Span), // Regions created as part of an automatic coercion - Coercion(TypeTrace<'tcx>), + Coercion(Span), // Region variables created as the values for early-bound regions EarlyBoundRegion(Span, ast::Name), @@ -343,8 +343,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, values: Types(expected_found(a_is_expected, a, b)) }; - let result = - cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b)); + let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).tys(a, b)); match result { Ok(t) => t, Err(ref err) => { @@ -362,9 +361,7 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, -> UnitResult<'tcx> { debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok(|| { - cx.sub_types(a_is_expected, origin, a, b) - }) + cx.sub_types(a_is_expected, origin, a, b) } pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -404,8 +401,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, -> UnitResult<'tcx> { debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok( - || cx.eq_types(a_is_expected, origin, a, b)) + cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b)) } pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -417,8 +413,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok( - || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, @@ -476,25 +471,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> CombineFields<'b, 'tcx> { + fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> CombineFields<'b, 'tcx> { CombineFields {infcx: self, a_is_expected: a_is_expected, trace: trace} } - pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Equate<'b, 'tcx> { + fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> Equate<'b, 'tcx> { Equate(self.combine_fields(a_is_expected, trace)) } - pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Sub<'b, 'tcx> { + fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> Sub<'b, 'tcx> { Sub(self.combine_fields(a_is_expected, trace)) } - pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Lub<'b, 'tcx> { + fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> Lub<'b, 'tcx> { Lub(self.combine_fields(a_is_expected, trace)) } @@ -558,11 +553,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Execute `f` and commit the bindings if successful + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` pub fn commit_if_ok(&self, f: F) -> Result where - F: FnOnce() -> Result + F: FnOnce(&CombinedSnapshot) -> Result { - self.commit_unconditionally(move || self.try(move |_| f())) + debug!("commit_if_ok()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); + match r { + Ok(_) => { self.commit_from(snapshot); } + Err(_) => { self.rollback_to(snapshot); } + } + r } /// Execute `f` and commit only the region bindings if successful. @@ -577,7 +580,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { float_snapshot, region_vars_snapshot } = self.start_snapshot(); - let r = self.try(move |_| f()); + let r = self.commit_if_ok(|_| f()); // Roll back any non-region bindings - they should be resolved // inside `f`, with, e.g. `resolve_type_vars_if_possible`. @@ -598,25 +601,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Execute `f`, unroll bindings on panic - pub fn try(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot) -> Result - { - debug!("try()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - debug!("try() -- r.is_ok() = {}", r.is_ok()); - match r { - Ok(_) => { - self.commit_from(snapshot); - } - Err(_) => { - self.rollback_to(snapshot); - } - } - r - } - /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot) -> R, @@ -643,7 +627,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> UnitResult<'tcx> { debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); self.sub(a_is_expected, trace).tys(a, b).map(|_| ()) }) @@ -656,7 +640,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { b: Ty<'tcx>) -> UnitResult<'tcx> { - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); self.equate(a_is_expected, trace).tys(a, b).map(|_| ()) }) @@ -672,7 +656,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("sub_trait_refs({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace { origin: origin, values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) @@ -691,7 +675,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("sub_poly_trait_refs({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) @@ -749,7 +733,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Span, predicate: &ty::PolyEquatePredicate<'tcx>) -> UnitResult<'tcx> { - self.try(|snapshot| { + self.commit_if_ok(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let origin = EquatePredicate(span); @@ -762,7 +746,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: Span, predicate: &ty::PolyRegionOutlivesPredicate) -> UnitResult<'tcx> { - self.try(|snapshot| { + self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let origin = RelateRegionParamBound(span); @@ -801,7 +785,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .new_key(None) } - pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region { + pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin))) } @@ -1253,14 +1237,14 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> { } } -impl<'tcx> RegionVariableOrigin<'tcx> { +impl RegionVariableOrigin { pub fn span(&self) -> Span { match *self { MiscVariable(a) => a, PatternRegion(a) => a, AddrOfRegion(a) => a, Autoref(a) => a, - Coercion(ref a) => a.span(), + Coercion(a) => a, EarlyBoundRegion(a, _) => a, LateBoundRegion(a, _, _) => a, BoundRegionInCoherence(_) => codemap::DUMMY_SP, @@ -1269,7 +1253,7 @@ impl<'tcx> RegionVariableOrigin<'tcx> { } } -impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> { +impl<'tcx> Repr<'tcx> for RegionVariableOrigin { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { MiscVariable(a) => { @@ -1282,7 +1266,7 @@ impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> { format!("AddrOfRegion({})", a.repr(tcx)) } Autoref(a) => format!("Autoref({})", a.repr(tcx)), - Coercion(ref a) => format!("Coercion({})", a.repr(tcx)), + Coercion(a) => format!("Coercion({})", a.repr(tcx)), EarlyBoundRegion(a, b) => { format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx)) } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index e7c5d1111a216..1d15656fea250 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -115,7 +115,7 @@ pub enum RegionResolutionError<'tcx> { /// Could not infer a value for `v` because `sub_r <= v` (due to /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and /// `sub_r <= sup_r` does not hold. - SubSupConflict(RegionVariableOrigin<'tcx>, + SubSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region), @@ -124,7 +124,7 @@ pub enum RegionResolutionError<'tcx> { /// Could not infer a value for `v` because `v <= r1` (due to /// `origin1`) and `v <= r2` (due to `origin2`) and /// `r1` and `r2` have no intersection. - SupSupConflict(RegionVariableOrigin<'tcx>, + SupSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region), @@ -132,7 +132,7 @@ pub enum RegionResolutionError<'tcx> { /// more specific errors message by suggesting to the user where they /// should put a lifetime. In those cases we process and put those errors /// into `ProcessedErrors` before we do any reporting. - ProcessedErrors(Vec>, + ProcessedErrors(Vec, Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>, Vec), } @@ -168,7 +168,7 @@ pub type CombineMap = FnvHashMap; pub struct RegionVarBindings<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - var_origins: RefCell>>, + var_origins: RefCell>, // Constraints of the form `A <= B` introduced by the region // checker. Here at least one of `A` and `B` must be a region @@ -316,7 +316,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { len as u32 } - pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid { + pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { let id = self.num_vars(); self.var_origins.borrow_mut().push(origin.clone()); let vid = RegionVid { index: id }; diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 1594d8b2e0d04..e27b910f6c26d 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -81,7 +81,7 @@ pub fn poly_project_and_unify_type<'cx,'tcx>( obligation.repr(selcx.tcx())); let infcx = selcx.infcx(); - infcx.try(|snapshot| { + infcx.commit_if_ok(|snapshot| { let (skol_predicate, skol_map) = infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9e4f63dca4565..740bed72d9b2d 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1242,7 +1242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let bound_self_ty = self.infcx.resolve_type_vars_if_possible(&obligation.self_ty()); let (self_ty, _) = @@ -1778,7 +1778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // For each type, produce a vector of resulting obligations let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let (skol_ty, skol_map) = self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = @@ -1888,7 +1888,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>) { let _: Result<(),()> = - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let result = self.match_projection_obligation_against_bounds_from_trait(obligation, snapshot); @@ -2043,7 +2043,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id, nested); - let trait_obligations: Result,()> = self.infcx.try(|snapshot| { + let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); @@ -2077,7 +2077,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let (skol_obligation_trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); let substs = diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d48927c61d2c7..0765d7294adf2 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,7 +76,7 @@ use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - trace: TypeTrace<'tcx> + origin: infer::TypeOrigin, } type CoerceResult<'tcx> = CombineResult<'tcx, Option>>; @@ -87,14 +87,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.tys(a, b)); + try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b)); Ok(None) // No coercion required. } - fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.regions(b, a)); + fn outlives(&self, + origin: infer::SubregionOrigin<'tcx>, + a: ty::Region, + b: ty::Region) + -> RelateResult<'tcx, ()> { + infer::mk_subr(self.fcx.infcx(), origin, b, a); Ok(()) } @@ -190,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { _ => return self.subtype(a, b) } - let coercion = Coercion(self.trace.clone()); + let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); @@ -214,7 +216,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let ty = ty::mk_rptr(self.tcx(), r_borrow, mt {ty: inner_ty, mutbl: mutbl_b}); - if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) { + if let Err(err) = self.subtype(ty, b) { if first_error.is_none() { first_error = Some(err); } @@ -264,12 +266,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(ty::terr_mutability); } - let coercion = Coercion(self.trace.clone()); + let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let ty = ty::mk_rptr(self.tcx(), self.tcx().mk_region(r_borrow), ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({:?})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -290,7 +292,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_ptr(self.tcx(), ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({:?})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -306,7 +308,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match self.unsize_ty(t_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.tcx(), ty); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({:?}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -365,9 +367,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); // relate `a1` to `b` - let result = self.fcx.infcx().try(|_| { + let result = self.fcx.infcx().commit_if_ok(|_| { // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(data_a.bounds.region_bound, + try!(self.outlives(infer::RelateObjectBound(self.origin.span()), + data_a.bounds.region_bound, data_b.bounds.region_bound)); self.subtype(ty_a1, ty_b) }); @@ -399,7 +402,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { + if self.subtype(*tp_a, *tp_b).is_ok() { continue; } match self.unsize_ty(*tp_a, *tp_b) { @@ -408,7 +411,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut new_substs = substs_a.clone(); new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); - if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { + if self.subtype(ty, ty_b).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), @@ -537,11 +540,10 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> CombineResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); let adjustment = try!(indent(|| { - fcx.infcx().commit_if_ok(|| { - let origin = infer::ExprAssignable(expr.span); + fcx.infcx().commit_if_ok(|_| { Coerce { fcx: fcx, - trace: infer::TypeTrace::types(origin, false, a, b) + origin: infer::ExprAssignable(expr.span), }.coerce(expr, a, b) }) })); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1c5f2c5607857..532277d75b2e0 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -282,7 +282,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); - let err = infcx.try(|snapshot| { + let err = infcx.commit_if_ok(|snapshot| { let origin = infer::MethodCompatCheck(impl_m_span); let (impl_sig, _) = diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 49f4399b2c7b4..2f7e0073e1751 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -95,7 +95,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( ty::lookup_item_type(tcx, self_type_did); let infcx = infer::new_infer_ctxt(tcx); - infcx.try(|snapshot| { + infcx.commit_if_ok(|snapshot| { let (named_type_to_skolem, skol_map) = infcx.construct_skolemized_subst(named_type_generics, snapshot); let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3edea6d300444..9171367468026 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1542,7 +1542,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, debug!("projection_bounds: outlives={} (2)", outlives.repr(tcx)); - let region_result = infcx.try(|_| { + let region_result = infcx.commit_if_ok(|_| { let (outlives, _) = infcx.replace_late_bound_regions_with_fresh_var( span, diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 0077d10e6ca82..4fba45e2a66c5 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -81,8 +81,8 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR cannot infer - //~| ERROR mismatched types + //~^ ERROR lifetime of the source pointer does not outlive lifetime bound + //~| ERROR cannot infer } fn main() { diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 70752cbfda19f..7fae530984f89 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR mismatched types + ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR mismatched types + ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 0f8bc6d684f12..10b883d4dc830 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR mismatched types + box v as Box //~ ERROR lifetime of the source pointer does not outlive } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index 8d05cb67e77b1..f3722690ef895 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR mismatched types + x //~ ERROR lifetime of the source pointer does not outlive //~^ ERROR cannot infer } From 7c62640458f1b8ac0f4d3871a265ea9555b3c3c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 15 Feb 2015 15:16:45 -0500 Subject: [PATCH 08/28] Refactor unification interface by moving the methods off of inferctxt and onto the `UnificationTable`, and renaming/collapsing some methods. --- src/librustc/middle/infer/combine.rs | 36 +++--- src/librustc/middle/infer/freshen.rs | 26 +++-- src/librustc/middle/infer/mod.rs | 16 ++- src/librustc/middle/infer/unify.rs | 161 +++++++++------------------ 4 files changed, 99 insertions(+), 140 deletions(-) diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 220a23b183a98..b3f4537f4728b 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -37,7 +37,6 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; use super::{InferCtxt, CombineResult}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; @@ -468,30 +467,29 @@ pub fn super_tys<'tcx, C>(this: &C, // Relate integral variables to other types (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), - a_id, b_id)); + try!(this.infcx().int_unification_table + .borrow_mut() + .unify_var_var(this.a_is_expected(), a_id, b_id)); Ok(a) } (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, IntType(v)) + unify_integral_variable(this, this.a_is_expected(), v_id, IntType(v)) } (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, IntType(v)) + unify_integral_variable(this, !this.a_is_expected(), v_id, IntType(v)) } (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, UintType(v)) + unify_integral_variable(this, this.a_is_expected(), v_id, UintType(v)) } (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, UintType(v)) + unify_integral_variable(this, !this.a_is_expected(), v_id, UintType(v)) } // Relate floating-point variables to other types (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); + try!(this.infcx().float_unification_table + .borrow_mut() + .unify_var_var(this.a_is_expected(), a_id, b_id)); Ok(a) } (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { @@ -617,8 +615,11 @@ pub fn super_tys<'tcx, C>(this: &C, vid: ty::IntVid, val: ty::IntVarValue) -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); + where C: Combine<'tcx> + { + try!(this.infcx().int_unification_table + .borrow_mut() + .unify_var_value(vid_is_expected, vid, val)); match val { IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), @@ -630,8 +631,11 @@ pub fn super_tys<'tcx, C>(this: &C, vid: ty::FloatVid, val: ast::FloatTy) -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); + where C: Combine<'tcx> + { + try!(this.infcx().float_unification_table + .borrow_mut() + .unify_var_value(vid_is_expected, vid, val)); Ok(ty::mk_mach_float(this.tcx(), val)) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index e41b949d5df1d..39a0a276b282e 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,7 +37,6 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, @@ -104,29 +103,34 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let tcx = self.infcx.tcx; + match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.freshen(self.infcx.type_variables.borrow().probe(v), - ty::TyVar(v), - ty::FreshTy) + self.freshen( + self.infcx.type_variables.borrow().probe(v), + ty::TyVar(v), + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::IntVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.int_unification_table.borrow_mut().probe(tcx, v), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.float_unification_table.borrow_mut().probe(tcx, v), + ty::FloatVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FreshTy(c)) | ty::ty_infer(ty::FreshIntTy(c)) => { if c >= self.freshen_count { - self.tcx().sess.bug( + tcx.sess.bug( &format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 31ce8503ed0ac..faca486e66985 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -43,7 +43,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; -use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes}; +use self::unify::UnificationTable; use self::error_reporting::ErrorReporting; pub mod bivariate; @@ -456,14 +456,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::ty_infer(ty::IntVar(vid)) => { - match self.int_unification_table.borrow_mut().get(self.tcx, vid).value { + match self.int_unification_table.borrow_mut().get(vid).value { None => UnconstrainedInt, _ => Neither, } }, ty::ty_infer(ty::FloatVar(vid)) => { - match self.float_unification_table.borrow_mut().get(self.tcx, vid).value { - None => return UnconstrainedFloat, + match self.float_unification_table.borrow_mut().get(vid).value { + None => UnconstrainedFloat, _ => Neither, } }, @@ -881,12 +881,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::ty_infer(ty::IntVar(v)) => { - self.probe_var(v) + self.int_unification_table + .borrow_mut() + .probe(self.tcx, v) .unwrap_or(typ) } ty::ty_infer(ty::FloatVar(v)) => { - self.probe_var(v) + self.float_unification_table + .borrow_mut() + .probe(self.tcx, v) .unwrap_or(typ) } diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index de96e9b49feee..e38d0bb5953ac 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -14,9 +14,7 @@ use std::marker; use middle::ty::{expected_found, IntVarValue}; use middle::ty::{self, Ty}; -use middle::infer::UnitResult; -use middle::infer::InferCtxt; -use std::cell::RefCell; +use middle::infer::{UnitResult}; use std::fmt::Debug; use std::marker::PhantomData; use syntax::ast; @@ -39,11 +37,6 @@ pub trait UnifyKey : Clone + Debug + PartialEq { fn from_index(u: usize) -> Self; - // Given an inference context, returns the unification table - // appropriate to this key type. - fn unification_table<'v>(infcx: &'v InferCtxt) - -> &'v RefCell>; - fn tag(k: Option) -> &'static str; } @@ -137,14 +130,18 @@ impl UnificationTable { k } - /// Find the root node for `vid`. This uses the standard union-find algorithm with path - /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure - pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node { + /// Find the root node for `vid`. This uses the standard + /// union-find algorithm with path compression: + /// . + /// + /// NB. This is a building-block operation and you would probably + /// prefer to call `probe` below. + pub fn get(&mut self, vid: K) -> Node { let index = vid.index(); let value = (*self.values.get(index)).clone(); match value { Redirect(redirect) => { - let node: Node = self.get(tcx, redirect.clone()); + let node: Node = self.get(redirect.clone()); if node.key != redirect { // Path compression self.values.set(index, Redirect(node.key.clone())); @@ -164,13 +161,9 @@ impl UnificationTable { } } - /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the - /// middle of a snapshot. - pub fn set<'tcx>(&mut self, - _tcx: &ty::ctxt<'tcx>, - key: K, - new_value: VarValue) - { + /// Sets the value for `vid` to `new_value`. `vid` MUST be a root + /// node! This is an internal operation used to impl other things. + fn set(&mut self, key: K, new_value: VarValue) { assert!(self.is_root(&key)); debug!("Updating variable {:?} to {:?}", @@ -179,37 +172,39 @@ impl UnificationTable { self.values.set(key.index(), new_value); } - /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns - /// the new root and rank. You should then update the value of the new root to something - /// suitable. - pub fn unify<'tcx>(&mut self, - tcx: &ty::ctxt<'tcx>, - node_a: &Node, - node_b: &Node) - -> (K, usize) - { + /// Either redirects `node_a` to `node_b` or vice versa, depending + /// on the relative rank. The value associated with the new root + /// will be `new_value`. + /// + /// NB: This is the "union" operation of "union-find". It is + /// really more of a building block. If the values associated with + /// your key are non-trivial, you would probably prefer to call + /// `unify_var_var` below. + pub fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", node_a.key, node_a.rank, node_b.key, node_b.rank); - if node_a.rank > node_b.rank { + let (new_root, new_rank) = if node_a.rank > node_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank) } else if node_a.rank < node_b.rank { // b has greater rank, so a should redirect to b. - self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone())); + self.set(node_a.key.clone(), Redirect(node_b.key.clone())); (node_b.key.clone(), node_b.rank) } else { // If equal, redirect one to the other and increment the // other's rank. assert_eq!(node_a.rank, node_b.rank); - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank + 1) - } + }; + + self.set(new_root, Root(new_value, new_rank)); } } @@ -223,8 +218,9 @@ impl sv::SnapshotVecDelegate for Delegate { } /////////////////////////////////////////////////////////////////////////// -// Code to handle simple keys like ints, floats---anything that -// doesn't have a subtyping relationship we need to worry about. +// Code to handle keys which carry a value, like ints, +// floats---anything that doesn't have a subtyping relationship we +// need to worry about. /// Indicates a type that does not have any kind of subtyping /// relationship. @@ -246,42 +242,19 @@ pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool, } } -pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, -{ - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> UnitResult<'tcx>; - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> UnitResult<'tcx>; - fn probe_var(&self, a_id: K) -> Option>; -} - -impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx> +impl<'tcx,K,V> UnificationTable where K : UnifyKey>, V : SimplyUnifiable<'tcx>, Option : UnifyValue, { - /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if - /// both keys have already been associated with a value, then those two values must be the - /// same. - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> UnitResult<'tcx> + pub fn unify_var_var(&mut self, + a_is_expected: bool, + a_id: K, + b_id: K) + -> UnitResult<'tcx> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a: Node = table.borrow_mut().get(tcx, a_id); - let node_b: Node = table.borrow_mut().get(tcx, b_id); + let node_a = self.get(a_id); + let node_b = self.get(b_id); let a_id = node_a.key.clone(); let b_id = node_b.key.clone(); @@ -304,46 +277,38 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx } }; - let (new_root, new_rank) = table.borrow_mut().unify(tcx, - &node_a, - &node_b); - table.borrow_mut().set(tcx, new_root, Root(combined, new_rank)); - return Ok(()) + Ok(self.unify(&node_a, &node_b, combined)) } /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// relationships, if `a_id` already has a value, it must be the same as `b`. - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> UnitResult<'tcx> + pub fn unify_var_value(&mut self, + a_is_expected: bool, + a_id: K, + b: V) + -> UnitResult<'tcx> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); + let node_a = self.get(a_id); let a_id = node_a.key.clone(); match node_a.value { None => { - table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank)); - return Ok(()); + self.set(a_id, Root(Some(b), node_a.rank)); + Ok(()) } Some(ref a_t) => { if *a_t == b { - return Ok(()); + Ok(()) } else { - return err(a_is_expected, (*a_t).clone(), b); + err(a_is_expected, (*a_t).clone(), b) } } } } - fn probe_var(&self, a_id: K) -> Option> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); + pub fn probe(&mut self, tcx: &ty::ctxt<'tcx>, a_id: K) -> Option> { + let node_a = self.get(a_id); match node_a.value { None => None, Some(ref a_t) => Some(a_t.to_type(tcx)) @@ -357,18 +322,9 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx impl UnifyKey for ty::IntVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.int_unification_table; - } - - fn tag(_: Option) -> &'static str { - "IntVid" - } + fn tag(_: Option) -> &'static str { "IntVid" } } impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue { @@ -390,18 +346,9 @@ impl UnifyValue for Option { } impl UnifyKey for ty::FloatVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.float_unification_table; - } - - fn tag(_: Option) -> &'static str { - "FloatVid" - } + fn tag(_: Option) -> &'static str { "FloatVid" } } impl UnifyValue for Option { From c581840dcce6991cf55379dd5cf8e2a92a94e994 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 16 Feb 2015 05:07:22 -0500 Subject: [PATCH 09/28] Make union-find helper fns private, change to u32. --- src/librustc/middle/infer/mod.rs | 14 ++++++++------ src/librustc/middle/infer/unify.rs | 30 ++++++++++++++++++------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index faca486e66985..15c3084703159 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -456,15 +456,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::ty_infer(ty::IntVar(vid)) => { - match self.int_unification_table.borrow_mut().get(vid).value { - None => UnconstrainedInt, - _ => Neither, + if self.int_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedInt } }, ty::ty_infer(ty::FloatVar(vid)) => { - match self.float_unification_table.borrow_mut().get(vid).value { - None => UnconstrainedFloat, - _ => Neither, + if self.float_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedFloat } }, _ => Neither, diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index e38d0bb5953ac..5effaca32b123 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -33,9 +33,9 @@ use util::snapshot_vec as sv; pub trait UnifyKey : Clone + Debug + PartialEq { type Value : UnifyValue; - fn index(&self) -> usize; + fn index(&self) -> u32; - fn from_index(u: usize) -> Self; + fn from_index(u: u32) -> Self; fn tag(k: Option) -> &'static str; } @@ -123,7 +123,7 @@ impl UnificationTable { pub fn new_key(&mut self, value: K::Value) -> K { let index = self.values.push(Root(value, 0)); - let k = UnifyKey::from_index(index); + let k = UnifyKey::from_index(index as u32); debug!("{}: created new key: {:?}", UnifyKey::tag(None::), k); @@ -136,8 +136,8 @@ impl UnificationTable { /// /// NB. This is a building-block operation and you would probably /// prefer to call `probe` below. - pub fn get(&mut self, vid: K) -> Node { - let index = vid.index(); + fn get(&mut self, vid: K) -> Node { + let index = vid.index() as usize; let value = (*self.values.get(index)).clone(); match value { Redirect(redirect) => { @@ -155,7 +155,8 @@ impl UnificationTable { } fn is_root(&self, key: &K) -> bool { - match *self.values.get(key.index()) { + let index = key.index() as usize; + match *self.values.get(index) { Redirect(..) => false, Root(..) => true, } @@ -169,7 +170,8 @@ impl UnificationTable { debug!("Updating variable {:?} to {:?}", key, new_value); - self.values.set(key.index(), new_value); + let index = key.index() as usize; + self.values.set(index, new_value); } /// Either redirects `node_a` to `node_b` or vice versa, depending @@ -180,7 +182,7 @@ impl UnificationTable { /// really more of a building block. If the values associated with /// your key are non-trivial, you would probably prefer to call /// `unify_var_var` below. - pub fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { + fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", node_a.key, node_a.rank, @@ -307,6 +309,10 @@ impl<'tcx,K,V> UnificationTable } } + pub fn has_value(&mut self, id: K) -> bool { + self.get(id).value.is_some() + } + pub fn probe(&mut self, tcx: &ty::ctxt<'tcx>, a_id: K) -> Option> { let node_a = self.get(a_id); match node_a.value { @@ -322,8 +328,8 @@ impl<'tcx,K,V> UnificationTable impl UnifyKey for ty::IntVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } fn tag(_: Option) -> &'static str { "IntVid" } } @@ -346,8 +352,8 @@ impl UnifyValue for Option { } impl UnifyKey for ty::FloatVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } fn tag(_: Option) -> &'static str { "FloatVid" } } From a6d9930525bee48e250bc9527f48c501e53d861d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 10 Mar 2015 15:32:25 -0400 Subject: [PATCH 10/28] Extract more `ty` and `infer` dependencies from the unification engine so that it is closer to standalone. --- src/librustc/middle/infer/combine.rs | 44 ++++++++++++++---- src/librustc/middle/infer/freshen.rs | 9 +++- src/librustc/middle/infer/mod.rs | 8 ++-- src/librustc/middle/infer/unify.rs | 65 +++++++-------------------- src/librustc_typeck/check/coercion.rs | 3 +- 5 files changed, 66 insertions(+), 63 deletions(-) diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index b3f4537f4728b..fdff750bf4690 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -436,8 +436,17 @@ pub fn expected_found<'tcx, C, T>(this: &C, a: T, b: T) -> ty::expected_found - where C: Combine<'tcx> { - if this.a_is_expected() { + where C: Combine<'tcx> +{ + expected_found_bool(this.a_is_expected(), a, b) +} + +fn expected_found_bool(a_is_expected: bool, + a: T, + b: T) + -> ty::expected_found +{ + if a_is_expected { ty::expected_found {expected: a, found: b} } else { ty::expected_found {expected: b, found: a} @@ -469,7 +478,8 @@ pub fn super_tys<'tcx, C>(this: &C, (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { try!(this.infcx().int_unification_table .borrow_mut() - .unify_var_var(this.a_is_expected(), a_id, b_id)); + .unify_var_var(a_id, b_id) + .map_err(|e| int_unification_error(this.a_is_expected(), e))); Ok(a) } (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { @@ -489,7 +499,8 @@ pub fn super_tys<'tcx, C>(this: &C, (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { try!(this.infcx().float_unification_table .borrow_mut() - .unify_var_var(this.a_is_expected(), a_id, b_id)); + .unify_var_var(a_id, b_id) + .map_err(|e| float_unification_error(this.a_is_expected(), e))); Ok(a) } (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { @@ -617,9 +628,11 @@ pub fn super_tys<'tcx, C>(this: &C, -> CombineResult<'tcx, Ty<'tcx>> where C: Combine<'tcx> { - try!(this.infcx().int_unification_table - .borrow_mut() - .unify_var_value(vid_is_expected, vid, val)); + try!(this.infcx() + .int_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| int_unification_error(vid_is_expected, e))); match val { IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), @@ -635,7 +648,8 @@ pub fn super_tys<'tcx, C>(this: &C, { try!(this.infcx().float_unification_table .borrow_mut() - .unify_var_value(vid_is_expected, vid, val)); + .unify_var_value(vid, val) + .map_err(|e| float_unification_error(vid_is_expected, e))); Ok(ty::mk_mach_float(this.tcx(), val)) } } @@ -863,3 +877,17 @@ impl<'tcx, T:Clone + PartialEq> CombineResultCompare<'tcx, T> for CombineResult< } } +fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) + -> ty::type_err<'tcx> +{ + let (a, b) = v; + ty::terr_int_mismatch(expected_found_bool(a_is_expected, a, b)) +} + +fn float_unification_error<'tcx>(a_is_expected: bool, + v: (ast::FloatTy, ast::FloatTy)) + -> ty::type_err<'tcx> +{ + let (a, b) = v; + ty::terr_float_mismatch(expected_found_bool(a_is_expected, a, b)) +} diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 39a0a276b282e..29f74d12ea3e8 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,6 +37,7 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; +use super::unify::ToType; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, @@ -115,14 +116,18 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::ty_infer(ty::IntVar(v)) => { self.freshen( - self.infcx.int_unification_table.borrow_mut().probe(tcx, v), + self.infcx.int_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), ty::IntVar(v), ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { self.freshen( - self.infcx.float_unification_table.borrow_mut().probe(tcx, v), + self.infcx.float_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), ty::FloatVar(v), ty::FreshIntTy) } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 15c3084703159..7e9c4d8e07688 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -43,7 +43,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; -use self::unify::UnificationTable; +use self::unify::{ToType, UnificationTable}; use self::error_reporting::ErrorReporting; pub mod bivariate; @@ -885,14 +885,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::ty_infer(ty::IntVar(v)) => { self.int_unification_table .borrow_mut() - .probe(self.tcx, v) + .probe(v) + .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } ty::ty_infer(ty::FloatVar(v)) => { self.float_unification_table .borrow_mut() - .probe(self.tcx, v) + .probe(v) + .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 5effaca32b123..a240917d6c1e4 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -14,7 +14,6 @@ use std::marker; use middle::ty::{expected_found, IntVarValue}; use middle::ty::{self, Ty}; -use middle::infer::{UnitResult}; use std::fmt::Debug; use std::marker::PhantomData; use syntax::ast; @@ -224,36 +223,15 @@ impl sv::SnapshotVecDelegate for Delegate { // floats---anything that doesn't have a subtyping relationship we // need to worry about. -/// Indicates a type that does not have any kind of subtyping -/// relationship. -pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; - fn to_type_err(expected_found) -> ty::type_err<'tcx>; -} - -pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool, - a_t: V, - b_t: V) - -> UnitResult<'tcx> { - if a_is_expected { - Err(SimplyUnifiable::to_type_err( - ty::expected_found {expected: a_t, found: b_t})) - } else { - Err(SimplyUnifiable::to_type_err( - ty::expected_found {expected: b_t, found: a_t})) - } -} - impl<'tcx,K,V> UnificationTable - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, + where K: UnifyKey>, + V: Clone+PartialEq, + Option: UnifyValue, { pub fn unify_var_var(&mut self, - a_is_expected: bool, a_id: K, b_id: K) - -> UnitResult<'tcx> + -> Result<(),(V,V)> { let node_a = self.get(a_id); let node_b = self.get(b_id); @@ -268,13 +246,13 @@ impl<'tcx,K,V> UnificationTable None } (&Some(ref v), &None) | (&None, &Some(ref v)) => { - Some((*v).clone()) + Some(v.clone()) } (&Some(ref v1), &Some(ref v2)) => { if *v1 != *v2 { - return err(a_is_expected, (*v1).clone(), (*v2).clone()) + return Err((v1.clone(), v2.clone())); } - Some((*v1).clone()) + Some(v1.clone()) } } }; @@ -285,10 +263,9 @@ impl<'tcx,K,V> UnificationTable /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// relationships, if `a_id` already has a value, it must be the same as `b`. pub fn unify_var_value(&mut self, - a_is_expected: bool, a_id: K, b: V) - -> UnitResult<'tcx> + -> Result<(),(V,V)> { let node_a = self.get(a_id); let a_id = node_a.key.clone(); @@ -303,7 +280,7 @@ impl<'tcx,K,V> UnificationTable if *a_t == b { Ok(()) } else { - err(a_is_expected, (*a_t).clone(), b) + Err((a_t.clone(), b)) } } } @@ -313,12 +290,8 @@ impl<'tcx,K,V> UnificationTable self.get(id).value.is_some() } - pub fn probe(&mut self, tcx: &ty::ctxt<'tcx>, a_id: K) -> Option> { - let node_a = self.get(a_id); - match node_a.value { - None => None, - Some(ref a_t) => Some(a_t.to_type(tcx)) - } + pub fn probe(&mut self, a_id: K) -> Option { + self.get(a_id).value.clone() } } @@ -326,6 +299,10 @@ impl<'tcx,K,V> UnificationTable // Integral type keys +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; +} + impl UnifyKey for ty::IntVid { type Value = Option; fn index(&self) -> u32 { self.index } @@ -333,17 +310,13 @@ impl UnifyKey for ty::IntVid { fn tag(_: Option) -> &'static str { "IntVid" } } -impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue { +impl<'tcx> ToType<'tcx> for IntVarValue { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match *self { ty::IntType(i) => ty::mk_mach_int(tcx, i), ty::UintType(i) => ty::mk_mach_uint(tcx, i), } } - - fn to_type_err(err: expected_found) -> ty::type_err<'tcx> { - return ty::terr_int_mismatch(err); - } } impl UnifyValue for Option { } @@ -360,12 +333,8 @@ impl UnifyKey for ty::FloatVid { impl UnifyValue for Option { } -impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy { +impl<'tcx> ToType<'tcx> for ast::FloatTy { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { ty::mk_mach_float(tcx, *self) } - - fn to_type_err(err: expected_found) -> ty::type_err<'tcx> { - ty::terr_float_mismatch(err) - } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 0765d7294adf2..1ba0194f84ecb 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,9 +62,8 @@ use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use middle::infer::{self, CombineResult, Coercion, TypeTrace}; +use middle::infer::{self, CombineResult, Coercion}; use middle::infer::combine::Combine; -use middle::infer::sub::Sub; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{self, mt, Ty}; From e78550bf88eac19b5a1b7a5c1dbad0d0c331c557 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Mar 2015 07:54:31 -0400 Subject: [PATCH 11/28] Switch to FnvHashMap --- src/librustc/middle/traits/select.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 740bed72d9b2d..8004cc37ccfd6 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -39,10 +39,10 @@ use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use std::cell::RefCell; -use std::collections::hash_map::HashMap; use std::rc::Rc; use syntax::{abi, ast}; use util::common::ErrorReported; +use util::nodemap::FnvHashMap; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { @@ -86,8 +86,8 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { #[derive(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, - SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, + hashmap: RefCell>, + SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } pub enum MethodMatchResult { @@ -2634,7 +2634,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { impl<'tcx> SelectionCache<'tcx> { pub fn new() -> SelectionCache<'tcx> { SelectionCache { - hashmap: RefCell::new(HashMap::new()) + hashmap: RefCell::new(FnvHashMap()) } } } From e301d7cab2d7f7dbbb6d5ee5d2fc1482f9fdd50d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Mar 2015 07:54:41 -0400 Subject: [PATCH 12/28] Remove unused import --- src/librustc/middle/infer/unify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index a240917d6c1e4..39271d4cdc597 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -12,7 +12,7 @@ pub use self::VarValue::*; use std::marker; -use middle::ty::{expected_found, IntVarValue}; +use middle::ty::{IntVarValue}; use middle::ty::{self, Ty}; use std::fmt::Debug; use std::marker::PhantomData; From 8403b82ddb6657dead95c6c3877824ffb3f13af2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Mar 2015 15:11:56 -0400 Subject: [PATCH 13/28] Port over type inference to using the new type relation stuff --- src/librustc/lib.rs | 1 + src/librustc/middle/infer/bivariate.rs | 93 ++- src/librustc/middle/infer/combine.rs | 704 +++--------------- src/librustc/middle/infer/equate.rs | 79 +- src/librustc/middle/infer/glb.rs | 82 +- .../middle/infer/higher_ranked/mod.rs | 129 ++-- src/librustc/middle/infer/lattice.rs | 46 +- src/librustc/middle/infer/lub.rs | 83 ++- src/librustc/middle/infer/mod.rs | 69 +- .../middle/infer/region_inference/mod.rs | 10 +- src/librustc/middle/infer/sub.rs | 88 ++- src/librustc/middle/traits/project.rs | 1 + src/librustc/middle/ty_fold.rs | 18 +- src/librustc/middle/ty_relate/mod.rs | 655 ++++++++++++++++ src/librustc/util/ppaux.rs | 6 + src/librustc_driver/test.rs | 18 +- src/librustc_typeck/check/coercion.rs | 8 +- src/librustc_typeck/coherence/mod.rs | 1 - src/test/compile-fail/dst-bad-coerce1.rs | 4 - 19 files changed, 1140 insertions(+), 955 deletions(-) create mode 100644 src/librustc/middle/ty_relate/mod.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index f31f8e8d4ce27..8a4790c17a405 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -122,6 +122,7 @@ pub mod middle { pub mod traits; pub mod ty; pub mod ty_fold; + pub mod ty_relate; pub mod ty_walk; pub mod weak_lang_items; } diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 91e1fea7ca52e..940dc75271c22 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -25,66 +25,54 @@ //! In particular, it might be enough to say (A,B) are bivariant for //! all (A,B). -use middle::ty::BuiltinBounds; +use super::combine::{self, CombineFields}; +use super::type_variable::{BiTo}; + use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::infer::combine::*; -use middle::infer::CombineResult; -use middle::infer::type_variable::BiTo; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; -pub struct Bivariate<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Bivariate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> { - Bivariate { fields: cf } +impl<'a, 'tcx> Bivariate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> { + Bivariate { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { - fn tag(&self) -> String { "Bivariate".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Bivariate" } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> - { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Contravariant => self.tys(a, b), - ty::Bivariant => self.tys(a, b), - } - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Contravariant => self.regions(a, b), - ty::Bivariant => self.regions(a, b), - } - } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions(&self, a: ty::Region, _: ty::Region) -> CombineResult<'tcx, ty::Region> { - Ok(a) - } - - fn builtin_bounds(&self, - a: BuiltinBounds, - b: BuiltinBounds) - -> CombineResult<'tcx, BuiltinBounds> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) + match variance { + // If we have Foo and Foo is invariant w/r/t A, + // and we want to assert that + // + // Foo <: Foo || + // Foo <: Foo + // + // then still A must equal B. + ty::Invariant => self.relate(a, b), + + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.relate(a, b), + ty::Contravariant => self.relate(a, b), } } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -109,17 +97,22 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> { let a1 = ty::erase_late_bound_regions(self.tcx(), a); let b1 = ty::erase_late_bound_regions(self.tcx(), b); - let c = try!(Combineable::combine(self, &a1, &b1)); + let c = try!(self.relate(&a1, &b1)); Ok(ty::Binder(c)) } } diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index fdff750bf4690..86f12b669b35e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -37,394 +37,21 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::{InferCtxt, CombineResult}; +use super::{InferCtxt}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; -use middle::subst; -use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; -use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; +use middle::ty::{TyVar}; use middle::ty::{IntType, UintType}; -use middle::ty::BuiltinBounds; use middle::ty::{self, Ty}; use middle::ty_fold; use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::ty_relate::{self, Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; -use std::rc::Rc; -use syntax::ast::Unsafety; use syntax::ast; -use syntax::abi; use syntax::codemap::Span; -pub trait Combine<'tcx> : Sized { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx } - fn tag(&self) -> String; - - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>; - - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx } - fn a_is_expected(&self) -> bool { self.fields().a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() } - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() } - fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() } - - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) } - - fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> CombineResult<'tcx, ty::mt<'tcx>> { - debug!("{}.mts({}, {})", - self.tag(), - a.repr(self.tcx()), - b.repr(self.tcx())); - - if a.mutbl != b.mutbl { - Err(ty::terr_mutability) - } else { - let mutbl = a.mutbl; - let variance = match mutbl { - ast::MutImmutable => ty::Covariant, - ast::MutMutable => ty::Invariant, - }; - let ty = try!(self.tys_with_variance(variance, a.ty, b.ty)); - Ok(ty::mt {ty: ty, mutbl: mutbl}) - } - } - - fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>>; - - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>>; - - fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region>; - - fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region>; - - fn substs(&self, - item_def_id: ast::DefId, - a_subst: &subst::Substs<'tcx>, - b_subst: &subst::Substs<'tcx>) - -> CombineResult<'tcx, subst::Substs<'tcx>> - { - debug!("substs: item_def_id={} a_subst={} b_subst={}", - item_def_id.repr(self.infcx().tcx), - a_subst.repr(self.infcx().tcx), - b_subst.repr(self.infcx().tcx)); - - let variances = if self.infcx().tcx.variance_computed.get() { - Some(ty::item_variances(self.infcx().tcx, item_def_id)) - } else { - None - }; - self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst) - } - - fn substs_variances(&self, - variances: Option<&ty::ItemVariances>, - a_subst: &subst::Substs<'tcx>, - b_subst: &subst::Substs<'tcx>) - -> CombineResult<'tcx, subst::Substs<'tcx>> - { - let mut substs = subst::Substs::empty(); - - for &space in &subst::ParamSpace::all() { - let a_tps = a_subst.types.get_slice(space); - let b_tps = b_subst.types.get_slice(space); - let t_variances = variances.map(|v| v.types.get_slice(space)); - let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps)); - substs.types.replace(space, tps); - } - - match (&a_subst.regions, &b_subst.regions) { - (&ErasedRegions, _) | (_, &ErasedRegions) => { - substs.regions = ErasedRegions; - } - - (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { - for &space in &subst::ParamSpace::all() { - let a_regions = a.get_slice(space); - let b_regions = b.get_slice(space); - let r_variances = variances.map(|v| v.regions.get_slice(space)); - let regions = try!(relate_region_params(self, - r_variances, - a_regions, - b_regions)); - substs.mut_regions().replace(space, regions); - } - } - } - - return Ok(substs); - - fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C, - variances: Option<&[ty::Variance]>, - a_tys: &[Ty<'tcx>], - b_tys: &[Ty<'tcx>]) - -> CombineResult<'tcx, Vec>> - { - if a_tys.len() != b_tys.len() { - return Err(ty::terr_ty_param_size(expected_found(this, - a_tys.len(), - b_tys.len()))); - } - - (0.. a_tys.len()).map(|i| { - let a_ty = a_tys[i]; - let b_ty = b_tys[i]; - let v = variances.map_or(ty::Invariant, |v| v[i]); - this.tys_with_variance(v, a_ty, b_ty) - }).collect() - } - - fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C, - variances: Option<&[ty::Variance]>, - a_rs: &[ty::Region], - b_rs: &[ty::Region]) - -> CombineResult<'tcx, Vec> - { - let tcx = this.infcx().tcx; - let num_region_params = a_rs.len(); - - debug!("relate_region_params(\ - a_rs={}, \ - b_rs={}, - variances={})", - a_rs.repr(tcx), - b_rs.repr(tcx), - variances.repr(tcx)); - - assert_eq!(num_region_params, - variances.map_or(num_region_params, - |v| v.len())); - - assert_eq!(num_region_params, b_rs.len()); - - (0..a_rs.len()).map(|i| { - let a_r = a_rs[i]; - let b_r = b_rs[i]; - let variance = variances.map_or(ty::Invariant, |v| v[i]); - this.regions_with_variance(variance, a_r, b_r) - }).collect() - } - } - - fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>, - b: &ty::BareFnTy<'tcx>) -> CombineResult<'tcx, ty::BareFnTy<'tcx>> { - let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); - let abi = try!(self.abi(a.abi, b.abi)); - let sig = try!(self.binders(&a.sig, &b.sig)); - Ok(ty::BareFnTy {unsafety: unsafety, - abi: abi, - sig: sig}) - } - - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> CombineResult<'tcx, ty::FnSig<'tcx>> { - if a.variadic != b.variadic { - return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic))); - } - - let inputs = try!(argvecs(self, - &a.inputs, - &b.inputs)); - - let output = try!(match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(ty::terr_convergence_mismatch( - expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))), - }); - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - - - fn argvecs<'tcx, C>(combiner: &C, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> CombineResult<'tcx, Vec>> - where C: Combine<'tcx> { - if a_args.len() == b_args.len() { - a_args.iter().zip(b_args.iter()) - .map(|(a, b)| combiner.args(*a, *b)).collect() - } else { - Err(ty::terr_arg_count) - } - } - } - - fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { - self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t)) - } - - fn unsafeties(&self, a: Unsafety, b: Unsafety) -> CombineResult<'tcx, Unsafety> { - if a != b { - Err(ty::terr_unsafety_mismatch(expected_found(self, a, b))) - } else { - Ok(a) - } - } - - fn abi(&self, a: abi::Abi, b: abi::Abi) -> CombineResult<'tcx, abi::Abi> { - if a == b { - Ok(a) - } else { - Err(ty::terr_abi_mismatch(expected_found(self, a, b))) - } - } - - fn projection_tys(&self, - a: &ty::ProjectionTy<'tcx>, - b: &ty::ProjectionTy<'tcx>) - -> CombineResult<'tcx, ty::ProjectionTy<'tcx>> - { - if a.item_name != b.item_name { - Err(ty::terr_projection_name_mismatched( - expected_found(self, a.item_name, b.item_name))) - } else { - let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref)); - Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) - } - } - - fn projection_predicates(&self, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>) - -> CombineResult<'tcx, ty::ProjectionPredicate<'tcx>> - { - let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty)); - let ty = try!(self.tys(a.ty, b.ty)); - Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) - } - - fn projection_bounds(&self, - a: &Vec>, - b: &Vec>) - -> CombineResult<'tcx, Vec>> - { - // To be compatible, `a` and `b` must be for precisely the - // same set of traits and item names. We always require that - // projection bounds lists are sorted by trait-def-id and item-name, - // so we can just iterate through the lists pairwise, so long as they are the - // same length. - if a.len() != b.len() { - Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len()))) - } else { - a.iter() - .zip(b.iter()) - .map(|(a, b)| self.binders(a, b)) - .collect() - } - } - - fn existential_bounds(&self, - a: &ty::ExistentialBounds<'tcx>, - b: &ty::ExistentialBounds<'tcx>) - -> CombineResult<'tcx, ty::ExistentialBounds<'tcx>> - { - let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound)); - let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); - let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds)); - Ok(ty::ExistentialBounds { region_bound: r, - builtin_bounds: nb, - projection_bounds: pb }) - } - - fn builtin_bounds(&self, - a: BuiltinBounds, - b: BuiltinBounds) - -> CombineResult<'tcx, BuiltinBounds> - { - // Two sets of builtin bounds are only relatable if they are - // precisely the same (but see the coercion code). - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) - } - } - - fn trait_refs(&self, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> CombineResult<'tcx, ty::TraitRef<'tcx>> - { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id))) - } else { - let substs = try!(self.substs(a.def_id, a.substs, b.substs)); - Ok(ty::TraitRef { def_id: a.def_id, substs: self.tcx().mk_substs(substs) }) - } - } - - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx>; - // this must be overridden to do correctly, so as to account for higher-ranked - // behavior -} - -pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { - fn combine>(combiner: &C, a: &Self, b: &Self) -> CombineResult<'tcx, Self>; -} - -impl<'tcx,T> Combineable<'tcx> for Rc - where T : Combineable<'tcx> -{ - fn combine(combiner: &C, - a: &Rc, - b: &Rc) - -> CombineResult<'tcx, Rc> - where C: Combine<'tcx> { - Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) - } -} - -impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { - fn combine(combiner: &C, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> CombineResult<'tcx, ty::TraitRef<'tcx>> - where C: Combine<'tcx> { - combiner.trait_refs(a, b) - } -} - -impl<'tcx> Combineable<'tcx> for Ty<'tcx> { - fn combine(combiner: &C, - a: &Ty<'tcx>, - b: &Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - combiner.tys(*a, *b) - } -} - -impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> { - fn combine(combiner: &C, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>) - -> CombineResult<'tcx, ty::ProjectionPredicate<'tcx>> - where C: Combine<'tcx> { - combiner.projection_predicates(a, b) - } -} - -impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> { - fn combine(combiner: &C, - a: &ty::FnSig<'tcx>, - b: &ty::FnSig<'tcx>) - -> CombineResult<'tcx, ty::FnSig<'tcx>> - where C: Combine<'tcx> { - combiner.fn_sigs(a, b) - } -} - #[derive(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -432,253 +59,133 @@ pub struct CombineFields<'a, 'tcx: 'a> { pub trace: TypeTrace<'tcx>, } -pub fn expected_found<'tcx, C, T>(this: &C, - a: T, - b: T) - -> ty::expected_found - where C: Combine<'tcx> -{ - expected_found_bool(this.a_is_expected(), a, b) -} - -fn expected_found_bool(a_is_expected: bool, - a: T, - b: T) - -> ty::expected_found +pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, + relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> { - if a_is_expected { - ty::expected_found {expected: a, found: b} - } else { - ty::expected_found {expected: b, found: a} - } -} - -pub fn super_tys<'tcx, C>(this: &C, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - let tcx = this.infcx().tcx; - let a_sty = &a.sty; - let b_sty = &b.sty; - debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); - return match (a_sty, b_sty) { - // The "subtype" ought to be handling cases involving var: - (&ty::ty_infer(TyVar(_)), _) - | (_, &ty::ty_infer(TyVar(_))) => - tcx.sess.bug( - &format!("{}: bot and var types should have been handled ({},{})", - this.tag(), - a.repr(this.infcx().tcx), - b.repr(this.infcx().tcx))), - - (&ty::ty_err, _) | (_, &ty::ty_err) => Ok(tcx.types.err), + let a_is_expected = relation.a_is_expected(); + match (&a.sty, &b.sty) { // Relate integral variables to other types - (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { - try!(this.infcx().int_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| int_unification_error(this.a_is_expected(), e))); + (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => { + try!(infcx.int_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| int_unification_error(a_is_expected, e))); Ok(a) } - (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { - unify_integral_variable(this, this.a_is_expected(), v_id, IntType(v)) + (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, IntType(v)) } - (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), v_id, IntType(v)) + (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v)) } - (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => { - unify_integral_variable(this, this.a_is_expected(), v_id, UintType(v)) + (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, UintType(v)) } - (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), v_id, UintType(v)) + (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v)) } // Relate floating-point variables to other types - (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { - try!(this.infcx().float_unification_table - .borrow_mut() - .unify_var_var(a_id, b_id) - .map_err(|e| float_unification_error(this.a_is_expected(), e))); + (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => { + try!(infcx.float_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| float_unification_error(relation.a_is_expected(), e))); Ok(a) } - (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { - unify_float_variable(this, this.a_is_expected(), v_id, v) - } - (&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => { - unify_float_variable(this, !this.a_is_expected(), v_id, v) - } - - (&ty::ty_char, _) - | (&ty::ty_bool, _) - | (&ty::ty_int(_), _) - | (&ty::ty_uint(_), _) - | (&ty::ty_float(_), _) => { - if a == b { - Ok(a) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } - } - - (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if - a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a), - - (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) - } - - (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { - debug!("Trying to match traits {:?} and {:?}", a, b); - let principal = try!(this.binders(&a_.principal, &b_.principal)); - let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds)); - Ok(ty::mk_trait(tcx, principal, bounds)) - } - - (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) - } - - (&ty::ty_closure(a_id, a_substs), - &ty::ty_closure(b_id, b_substs)) - if a_id == b_id => { - // All ty_closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let substs = try!(this.substs_variances(None, a_substs, b_substs)); - Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) - } - - (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { - let typ = try!(this.tys(a_inner, b_inner)); - Ok(ty::mk_uniq(tcx, typ)) - } - - (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => { - let mt = try!(this.mts(a_mt, b_mt)); - Ok(ty::mk_ptr(tcx, mt)) - } - - (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => { - let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r)); - let mt = try!(this.mts(a_mt, b_mt)); - Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) - } - - (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => { - this.tys(a_t, b_t).and_then(|t| { - if sz_a == sz_b { - Ok(ty::mk_vec(tcx, t, Some(sz_a))) - } else { - Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b))) - } - }) - } - - (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => { - this.tys(a_t, b_t).and_then(|t| { - if sz_a == sz_b { - Ok(ty::mk_vec(tcx, t, sz_a)) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } - }) - } - - (&ty::ty_str, &ty::ty_str) => Ok(ty::mk_str(tcx)), - - (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => { - if as_.len() == bs.len() { - as_.iter().zip(bs.iter()) - .map(|(a, b)| this.tys(*a, *b)) - .collect::>() - .map(|ts| ty::mk_tup(tcx, ts)) - } else if as_.len() != 0 && bs.len() != 0 { - Err(ty::terr_tuple_size( - expected_found(this, as_.len(), bs.len()))) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } + (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => { + unify_float_variable(infcx, a_is_expected, v_id, v) } - - (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty)) - if a_opt_def_id == b_opt_def_id => - { - let fty = try!(this.bare_fn_tys(a_fty, b_fty)); - Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) + (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => { + unify_float_variable(infcx, !a_is_expected, v_id, v) } - (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => { - let projection_ty = try!(this.projection_tys(a_data, b_data)); - Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) + // All other cases of inference are errors + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => { + Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b))) } - _ => Err(ty::terr_sorts(expected_found(this, a, b))), - }; - fn unify_integral_variable<'tcx, C>(this: &C, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue) - -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> - { - try!(this.infcx() - .int_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| int_unification_error(vid_is_expected, e))); - match val { - IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), - UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), + _ => { + ty_relate::super_relate_tys(relation, a, b) } } +} - fn unify_float_variable<'tcx, C>(this: &C, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ast::FloatTy) - -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> - { - try!(this.infcx().float_unification_table - .borrow_mut() - .unify_var_value(vid, val) - .map_err(|e| float_unification_error(vid_is_expected, e))); - Ok(ty::mk_mach_float(this.tcx(), val)) +fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) + -> RelateResult<'tcx, Ty<'tcx>> +{ + try!(infcx + .int_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| int_unification_error(vid_is_expected, e))); + match val { + IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)), + UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)), } } -impl<'f, 'tcx> CombineFields<'f, 'tcx> { - pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> { +fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::FloatTy) + -> RelateResult<'tcx, Ty<'tcx>> +{ + try!(infcx + .float_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| float_unification_error(vid_is_expected, e))); + Ok(ty::mk_mach_float(infcx.tcx, val)) +} + +impl<'a, 'tcx> CombineFields<'a, 'tcx> { + pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.infcx.tcx + } + + pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> { CombineFields { a_is_expected: !self.a_is_expected, ..(*self).clone() } } - fn equate(&self) -> Equate<'f, 'tcx> { - Equate((*self).clone()) + pub fn equate(&self) -> Equate<'a, 'tcx> { + Equate::new(self.clone()) + } + + pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { + Bivariate::new(self.clone()) + } + + pub fn sub(&self) -> Sub<'a, 'tcx> { + Sub::new(self.clone()) } - fn bivariate(&self) -> Bivariate<'f, 'tcx> { - Bivariate((*self).clone()) + pub fn lub(&self) -> Lub<'a, 'tcx> { + Lub::new(self.clone()) } - fn sub(&self) -> Sub<'f, 'tcx> { - Sub((*self).clone()) + pub fn glb(&self) -> Glb<'a, 'tcx> { + Glb::new(self.clone()) } pub fn instantiate(&self, a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid) - -> CombineResult<'tcx, ()> + -> RelateResult<'tcx, ()> { let tcx = self.infcx.tcx; let mut stack = Vec::new(); @@ -742,15 +249,12 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - match dir { - BiTo => try!(self.bivariate().tys(a_ty, b_ty)), - - EqTo => try!(self.equate().tys(a_ty, b_ty)), - - SubtypeOf => try!(self.sub().tys(a_ty, b_ty)), - - SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)), - }; + try!(match dir { + BiTo => self.bivariate().relate(&a_ty, &b_ty), + EqTo => self.equate().relate(&a_ty, &b_ty), + SubtypeOf => self.sub().relate(&a_ty, &b_ty), + SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), + }); } Ok(()) @@ -764,7 +268,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { ty: Ty<'tcx>, for_vid: ty::TyVid, make_region_vars: bool) - -> CombineResult<'tcx, Ty<'tcx>> + -> RelateResult<'tcx, Ty<'tcx>> { let mut generalize = Generalizer { infcx: self.infcx, @@ -858,18 +362,18 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { } } -pub trait CombineResultCompare<'tcx, T> { - fn compare(&self, t: T, f: F) -> CombineResult<'tcx, T> where +pub trait RelateResultCompare<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where F: FnOnce() -> ty::type_err<'tcx>; } -impl<'tcx, T:Clone + PartialEq> CombineResultCompare<'tcx, T> for CombineResult<'tcx, T> { - fn compare(&self, t: T, f: F) -> CombineResult<'tcx, T> where +impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where F: FnOnce() -> ty::type_err<'tcx>, { - (*self).clone().and_then(|s| { + self.clone().and_then(|s| { if s == t { - (*self).clone() + self.clone() } else { Err(f()) } @@ -881,7 +385,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int -> ty::type_err<'tcx> { let (a, b) = v; - ty::terr_int_mismatch(expected_found_bool(a_is_expected, a, b)) + ty::terr_int_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) } fn float_unification_error<'tcx>(a_is_expected: bool, @@ -889,5 +393,5 @@ fn float_unification_error<'tcx>(a_is_expected: bool, -> ty::type_err<'tcx> { let (a, b) = v; - ty::terr_float_mismatch(expected_found_bool(a_is_expected, a, b)) + ty::terr_float_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 59394d1dd3715..2003f459d89b4 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -8,51 +8,43 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::combine::{self, CombineFields}; +use super::higher_ranked::HigherRankedRelations; +use super::{Subtype}; +use super::type_variable::{EqTo}; + use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::infer::combine::*; -use middle::infer::CombineResult; -use middle::infer::Subtype; -use middle::infer::type_variable::EqTo; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; -pub struct Equate<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Equate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> { - Equate { fields: cf } +impl<'a, 'tcx> Equate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> { + Equate { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { - fn tag(&self) -> String { "Equate".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Equate" } - fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> - { - // Once we're equating, it doesn't matter what the variance is. - self.tys(a, b) - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region> - { - // Once we're equating, it doesn't matter what the variance is. - self.regions(a, b) - } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { - debug!("{}.regions({}, {})", - self.tag(), - a.repr(self.fields.infcx.tcx), - b.repr(self.fields.infcx.tcx)); - self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b); - Ok(a) + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -77,15 +69,26 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.fields.infcx.tcx), + b.repr(self.fields.infcx.tcx)); + let origin = Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_eqregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> { - try!(self.sub().binders(a, b)); - self.sub().binders(b, a) + try!(self.fields.higher_ranked_sub(a, b)); + self.fields.higher_ranked_sub(b, a) } } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 28c0b4df7f402..5822fb0f2d432 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -8,67 +8,79 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; -use super::lattice::*; +use super::combine::CombineFields; use super::higher_ranked::HigherRankedRelations; -use super::CombineResult; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; /// "Greatest lower bound" (common subtype) -pub struct Glb<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Glb<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> { - Glb { fields: cf } +impl<'a, 'tcx> Glb<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> { + Glb { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { - fn tag(&self) -> String { "Glb".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { + fn tag(&self) -> &'static str { "Glb" } + + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => self.lub().tys(a, b), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.lub().relate(a, b), } } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => self.lub().regions(a, b), - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); - Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { - super_lattice_tys(self, a, b) + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_glb(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.higher_ranked_glb(a, b) +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + try!(sub.relate(&v, &a)); + try!(sub.relate(&v, &b)); + Ok(()) } } diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 9280ffd06545a..f347d28b93c2b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,25 +11,26 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{CombinedSnapshot, CombineResult, InferCtxt, HigherRankedType, SkolemizationMap}; -use super::combine::{Combine, Combineable}; +use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::combine::CombineFields; use middle::subst; use middle::ty::{self, Binder}; use middle::ty_fold::{self, TypeFoldable}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::Repr; -pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx>; +pub trait HigherRankedRelations<'a,'tcx> { + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; } trait InferCtxtExt { @@ -40,15 +41,15 @@ trait InferCtxtExt { -> Vec; } -impl<'tcx,C> HigherRankedRelations<'tcx> for C - where C : Combine<'tcx> -{ +impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { fn higher_ranked_sub(&self, a: &Binder, b: &Binder) - -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx> + -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { + let tcx = self.infcx.tcx; + debug!("higher_ranked_sub(a={}, b={})", - a.repr(self.tcx()), b.repr(self.tcx())); + a.repr(tcx), b.repr(tcx)); // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure @@ -60,32 +61,32 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().commit_if_ok(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // First, we instantiate each bound region in the subtype with a fresh // region variable. let (a_prime, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, a); // Second, we instantiate each bound region in the supertype with a // fresh concrete region. let (b_prime, skol_map) = - self.infcx().skolemize_late_bound_regions(b, snapshot); + self.infcx.skolemize_late_bound_regions(b, snapshot); - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); + debug!("a_prime={}", a_prime.repr(tcx)); + debug!("b_prime={}", b_prime.repr(tcx)); // Compare types now that bound regions have been replaced. - let result = try!(Combineable::combine(self, &a_prime, &b_prime)); + let result = try!(self.sub().relate(&a_prime, &b_prime)); // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - match leak_check(self.infcx(), &skol_map, snapshot) { + match leak_check(self.infcx, &skol_map, snapshot) { Ok(()) => { } Err((skol_br, tainted_region)) => { - if self.a_is_expected() { + if self.a_is_expected { debug!("Not as polymorphic!"); return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, tainted_region)); @@ -98,42 +99,42 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + result.repr(tcx)); Ok(ty::Binder(result)) }); } - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().commit_if_ok(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); + let span = self.trace.origin.span(); let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( + self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, a); let (b_with_fresh, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( + self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, b); // Collect constraints. let result0 = - try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + try!(self.lub().relate(&a_with_fresh, &b_with_fresh)); let result0 = - self.infcx().resolve_type_vars_if_possible(&result0); + self.infcx.resolve_type_vars_if_possible(&result0); debug!("lub result0 = {}", result0.repr(self.tcx())); // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); - let span = self.trace().origin.span(); + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); let result1 = fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, &new_vars, &a_map, r)); debug!("lub({},{}) = {}", @@ -194,40 +195,40 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> CombineResult<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { - debug!("{}.higher_ranked_glb({}, {})", - self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); + debug!("higher_ranked_glb({}, {})", + a.repr(self.tcx()), b.repr(self.tcx())); // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().commit_if_ok(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, a); + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, a); let (b_with_fresh, b_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, b); + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); // Collect constraints. let result0 = - try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + try!(self.glb().relate(&a_with_fresh, &b_with_fresh)); let result0 = - self.infcx().resolve_type_vars_if_possible(&result0); + self.infcx.resolve_type_vars_if_possible(&result0); debug!("glb result0 = {}", result0.repr(self.tcx())); // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); - let span = self.trace().origin.span(); + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); let result1 = fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, &new_vars, &a_map, &a_vars, &b_vars, r)); @@ -332,17 +333,19 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } -fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, - map: &FnvHashMap) - -> Vec { - map.iter().map(|(_, r)| match *r { - ty::ReInfer(ty::ReVar(r)) => { r } - r => { - combiner.infcx().tcx.sess.span_bug( - combiner.trace().origin.span(), - &format!("found non-region-vid: {:?}", r)); - } - }).collect() +fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, + map: &FnvHashMap) + -> Vec { + map.iter() + .map(|(_, r)| match *r { + ty::ReInfer(ty::ReVar(r)) => { r } + r => { + fields.tcx().sess.span_bug( + fields.trace.origin.span(), + &format!("found non-region-vid: {:?}", r)); + } + }) + .collect() } fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { @@ -356,8 +359,8 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, unbound_value: &T, mut fldr: F) -> T - where T : Combineable<'tcx>, - F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, + where T: TypeFoldable<'tcx>, + F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 6cbf20f26aefd..57001083b03e2 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -29,48 +29,32 @@ //! over a `LatticeValue`, which is a value defined with respect to //! a lattice. -use super::*; -use super::combine::*; -use super::glb::Glb; -use super::lub::Lub; +use super::combine; +use super::InferCtxt; use middle::ty::TyVar; use middle::ty::{self, Ty}; +use middle::ty_relate::{RelateResult, TypeRelation}; use util::ppaux::Repr; -pub trait LatticeDir<'tcx> { +pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> { + fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; + // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()>; -} - -impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()> { - let sub = self.sub(); - try!(sub.tys(a, v)); - try!(sub.tys(b, v)); - Ok(()) - } -} - -impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, ()> { - let sub = self.sub(); - try!(sub.tys(v, a)); - try!(sub.tys(v, b)); - Ok(()) - } + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } -pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> +pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where 'tcx: 'a { debug!("{}.lattice_tys({}, {})", this.tag(), - a.repr(this.infcx().tcx), - b.repr(this.infcx().tcx)); + a.repr(this.tcx()), + b.repr(this.tcx())); if a == b { return Ok(a); @@ -95,7 +79,7 @@ pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L, } _ => { - super_tys(this, a, b) + combine::super_combine_tys(this.infcx(), this, a, b) } } } diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 123b6cbcc0a6c..f456687be13ac 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -8,67 +8,80 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; +use super::combine::CombineFields; use super::higher_ranked::HigherRankedRelations; -use super::lattice::*; -use super::CombineResult; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; /// "Least upper bound" (common supertype) -pub struct Lub<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Lub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> { - Lub { fields: cf } +impl<'a, 'tcx> Lub<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> { + Lub { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { - fn tag(&self) -> String { "Lub".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Lub" } + + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => self.glb().tys(a, b), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.glb().relate(a, b), } } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => self.glb().regions(a, b), - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { - super_lattice_tys(self, a, b) + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_lub(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.higher_ranked_lub(a, b) +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + try!(sub.relate(&a, &v)); + try!(sub.relate(&b, &v)); + Ok(()) } } + diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 7e9c4d8e07688..da811c354578d 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -28,7 +28,8 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric}; use middle::ty::replace_late_bound_regions; use middle::ty::{self, Ty}; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use std::cell::RefCell; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use std::cell::{RefCell}; use std::fmt; use std::rc::Rc; use syntax::ast; @@ -38,11 +39,8 @@ use util::nodemap::FnvHashMap; use util::ppaux::ty_to_string; use util::ppaux::{Repr, UserString}; -use self::combine::{Combine, Combineable, CombineFields}; +use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::equate::Equate; -use self::sub::Sub; -use self::lub::Lub; use self::unify::{ToType, UnificationTable}; use self::error_reporting::ErrorReporting; @@ -62,9 +60,7 @@ pub mod type_variable; pub mod unify; pub type Bound = Option; - -pub type CombineResult<'tcx, T> = Result>; // "combine result" -pub type UnitResult<'tcx> = CombineResult<'tcx, ()>; // "unify result" +pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type fres = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { @@ -343,7 +339,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, values: Types(expected_found(a_is_expected, a, b)) }; - let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).tys(a, b)); + let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b)); match result { Ok(t) => t, Err(ref err) => { @@ -374,11 +370,12 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).tys(a, b).map(|_| ()) + cx.sub(true, trace).relate(&a, &b).map(|_| ()) }) } -pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> UnitResult<'tcx> +pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) + -> UnitResult<'tcx> { cx.can_equate(&a, &b) } @@ -473,26 +470,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> CombineFields<'b, 'tcx> { + fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> CombineFields<'a, 'tcx> { CombineFields {infcx: self, a_is_expected: a_is_expected, trace: trace} } - fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Equate<'b, 'tcx> { - Equate(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> equate::Equate<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).equate() } - fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Sub<'b, 'tcx> { - Sub(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> sub::Sub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).sub() } - fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Lub<'b, 'tcx> { - Lub(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> lub::Lub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).lub() + } + + // public so that it can be used from the rustc_driver unit tests + pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> glb::Glb<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).glb() } fn start_snapshot(&self) -> CombinedSnapshot { @@ -631,7 +641,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.sub(a_is_expected, trace).tys(a, b).map(|_| ()) + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -644,7 +654,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.equate(a_is_expected, trace).tys(a, b).map(|_| ()) + self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -663,7 +673,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).trait_refs(&*a, &*b).map(|_| ()) + self.sub(a_is_expected, trace).relate(&*a, &*b).map(|_| ()) }) } @@ -682,7 +692,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).binders(&a, &b).map(|_| ()) + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -1045,8 +1055,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bs); } - pub fn can_equate(&self, a: &T, b: &T) -> UnitResult<'tcx> - where T : Combineable<'tcx> + Repr<'tcx> + pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> + where T: Relate<'b,'tcx> + Repr<'tcx> { debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx)); self.probe(|_| { @@ -1057,8 +1067,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let e = self.tcx.types.err; let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, e, e)) }; - let eq = self.equate(true, trace); - Combineable::combine(&eq, a, b) + self.equate(true, trace).relate(a, b) }).map(|_| ()) } } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 1d15656fea250..45d4a8c5d9f34 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -18,7 +18,6 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use self::Classification::*; -use super::CombineResult; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use middle::region; @@ -26,6 +25,7 @@ use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty_relate::RelateResult; use middle::graph; use middle::graph::{Direction, NodeIndex}; use util::common::indenter; @@ -825,7 +825,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn glb_concrete_regions(&self, a: Region, b: Region) - -> CombineResult<'tcx, Region> + -> RelateResult<'tcx, Region> { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { @@ -901,7 +901,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn glb_free_regions(&self, a: &FreeRegion, b: &FreeRegion) - -> CombineResult<'tcx, ty::Region> + -> RelateResult<'tcx, ty::Region> { return match a.cmp(b) { Less => helper(self, a, b), @@ -911,7 +911,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, a: &FreeRegion, - b: &FreeRegion) -> CombineResult<'tcx, ty::Region> + b: &FreeRegion) -> RelateResult<'tcx, ty::Region> { if this.tcx.region_maps.sub_free_region(*a, *b) { Ok(ty::ReFree(*a)) @@ -930,7 +930,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { region_b: ty::Region, scope_a: region::CodeExtent, scope_b: region::CodeExtent) - -> CombineResult<'tcx, Region> + -> RelateResult<'tcx, Region> { // We want to generate the intersection of two // scopes or two free regions. So, if one of diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index d58a911e86064..31b654a5b3fd3 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -8,64 +8,49 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; -use super::CombineResult; +use super::combine::{self, CombineFields}; use super::higher_ranked::HigherRankedRelations; use super::Subtype; use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; /// "Greatest lower bound" (common subtype) -pub struct Sub<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Sub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> { - Sub { fields: cf } +impl<'a, 'tcx> Sub<'a, 'tcx> { + pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> { + Sub { fields: f } + } } -impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { - fn tag(&self) -> String { "Sub".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } - - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, Ty<'tcx>> - { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a), - } - } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Sub" } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> CombineResult<'tcx, ty::Region> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), } } - fn regions(&self, a: ty::Region, b: ty::Region) -> CombineResult<'tcx, ty::Region> { - debug!("{}.regions({}, {})", - self.tag(), - a.repr(self.tcx()), - b.repr(self.tcx())); - self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b); - Ok(a) - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CombineResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({}, {})", self.tag(), - a.repr(self.tcx()), b.repr(self.tcx())); if a == b { return Ok(a); } let infcx = self.fields.infcx; @@ -80,8 +65,8 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } (&ty::ty_infer(TyVar(a_id)), _) => { try!(self.fields - .switch_expected() - .instantiate(b, SupertypeOf, a_id)); + .switch_expected() + .instantiate(b, SupertypeOf, a_id)); Ok(a) } (_, &ty::ty_infer(TyVar(b_id))) => { @@ -94,14 +79,25 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> CombineResult<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.tcx()), + b.repr(self.tcx())); + let origin = Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_subregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> { - self.higher_ranked_sub(a, b) + self.fields.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index e27b910f6c26d..7488b8f046e74 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -291,6 +291,7 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> { } } +#[derive(Clone)] pub struct Normalized<'tcx,T> { pub value: T, pub obligations: Vec>, diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f17ba78007bb2..5f77574f65ed4 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -39,6 +39,8 @@ use middle::subst::VecPerParamSpace; use middle::ty::{self, Ty}; use middle::traits; use std::rc::Rc; +use syntax::abi; +use syntax::ast; use syntax::owned_slice::OwnedSlice; use util::ppaux::Repr; @@ -47,7 +49,7 @@ use util::ppaux::Repr; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. -pub trait TypeFoldable<'tcx> { +pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone { fn fold_with>(&self, folder: &mut F) -> Self; } @@ -149,12 +151,20 @@ pub trait TypeFolder<'tcx> : Sized { // can easily refactor the folding into the TypeFolder trait as // needed. -impl<'tcx> TypeFoldable<'tcx> for () { - fn fold_with>(&self, _: &mut F) -> () { - () +macro_rules! CopyImpls { + ($($ty:ty),+) => { + $( + impl<'tcx> TypeFoldable<'tcx> for $ty { + fn fold_with>(&self, _: &mut F) -> $ty { + *self + } + } + )+ } } +CopyImpls! { (), ast::Unsafety, abi::Abi } + impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn fold_with>(&self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs new file mode 100644 index 0000000000000..1205b7d957930 --- /dev/null +++ b/src/librustc/middle/ty_relate/mod.rs @@ -0,0 +1,655 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generalized type relating mechanism. A type relation R relates a +//! pair of values (A, B). A and B are usually types or regions but +//! can be other things. Examples of type relations are subtyping, +//! type equality, etc. + +use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs}; +use middle::ty::{self, Ty}; +use middle::ty_fold::TypeFoldable; +use std::rc::Rc; +use syntax::abi; +use syntax::ast; +use util::ppaux::Repr; + +pub type RelateResult<'tcx, T> = Result>; + +pub trait TypeRelation<'a,'tcx> : Sized { + fn tcx(&self) -> &'a ty::ctxt<'tcx>; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Returns true if the value `a` is the "expected" type in the + /// relation. Just affects error messages. + fn a_is_expected(&self) -> bool; + + /// Generic relation routine suitable for most anything. + fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { + Relate::relate(self, a, b) + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T>; + + // Overrideable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>>; + + fn regions(&mut self, a: ty::Region, b: ty::Region) + -> RelateResult<'tcx, ty::Region>; + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx>; +} + +pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { + fn relate>(relation: &mut R, + a: &Self, + b: &Self) + -> RelateResult<'tcx, Self>; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> { + fn relate(relation: &mut R, + a: &ty::mt<'tcx>, + b: &ty::mt<'tcx>) + -> RelateResult<'tcx, ty::mt<'tcx>> + where R: TypeRelation<'a,'tcx> + { + debug!("{}.mts({}, {})", + relation.tag(), + a.repr(relation.tcx()), + b.repr(relation.tcx())); + if a.mutbl != b.mutbl { + Err(ty::terr_mutability) + } else { + let mutbl = a.mutbl; + let variance = match mutbl { + ast::MutImmutable => ty::Covariant, + ast::MutMutable => ty::Invariant, + }; + let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty)); + Ok(ty::mt {ty: ty, mutbl: mutbl}) + } + } +} + +// substitutions are not themselves relatable without more context, +// but they is an important subroutine for things that ARE relatable, +// like traits etc. +fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, + item_def_id: ast::DefId, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + debug!("substs: item_def_id={} a_subst={} b_subst={}", + item_def_id.repr(relation.tcx()), + a_subst.repr(relation.tcx()), + b_subst.repr(relation.tcx())); + + let variances; + let opt_variances = if relation.tcx().variance_computed.get() { + variances = ty::item_variances(relation.tcx(), item_def_id); + Some(&*variances) + } else { + None + }; + relate_substs(relation, opt_variances, a_subst, b_subst) +} + +fn relate_substs<'a,'tcx,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let mut substs = Substs::empty(); + + for &space in &ParamSpace::all() { + let a_tps = a_subst.types.get_slice(space); + let b_tps = b_subst.types.get_slice(space); + let t_variances = variances.map(|v| v.types.get_slice(space)); + let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps)); + substs.types.replace(space, tps); + } + + match (&a_subst.regions, &b_subst.regions) { + (&ErasedRegions, _) | (_, &ErasedRegions) => { + substs.regions = ErasedRegions; + } + + (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { + for &space in &ParamSpace::all() { + let a_regions = a.get_slice(space); + let b_regions = b.get_slice(space); + let r_variances = variances.map(|v| v.regions.get_slice(space)); + let regions = try!(relate_region_params(relation, + r_variances, + a_regions, + b_regions)); + substs.mut_regions().replace(space, regions); + } + } + } + + Ok(substs) +} + +fn relate_type_params<'a,'tcx,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_tys: &[Ty<'tcx>], + b_tys: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_tys.len() != b_tys.len() { + return Err(ty::terr_ty_param_size(expected_found(relation, + &a_tys.len(), + &b_tys.len()))); + } + + (0 .. a_tys.len()) + .map(|i| { + let a_ty = a_tys[i]; + let b_ty = b_tys[i]; + let v = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(v, &a_ty, &b_ty) + }) + .collect() +} + +fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_rs: &[ty::Region], + b_rs: &[ty::Region]) + -> RelateResult<'tcx, Vec> + where R: TypeRelation<'a,'tcx> +{ + let tcx = relation.tcx(); + let num_region_params = a_rs.len(); + + debug!("relate_region_params(a_rs={}, \ + b_rs={}, variances={})", + a_rs.repr(tcx), + b_rs.repr(tcx), + variances.repr(tcx)); + + assert_eq!(num_region_params, + variances.map_or(num_region_params, + |v| v.len())); + + assert_eq!(num_region_params, b_rs.len()); + + (0..a_rs.len()) + .map(|i| { + let a_r = a_rs[i]; + let b_r = b_rs[i]; + let variance = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(variance, &a_r, &b_r) + }) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::BareFnTy<'tcx>, + b: &ty::BareFnTy<'tcx>) + -> RelateResult<'tcx, ty::BareFnTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety)); + let abi = try!(relation.relate(&a.abi, &b.abi)); + let sig = try!(relation.relate(&a.sig, &b.sig)); + Ok(ty::BareFnTy {unsafety: unsafety, + abi: abi, + sig: sig}) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { + fn relate(relation: &mut R, + a: &ty::FnSig<'tcx>, + b: &ty::FnSig<'tcx>) + -> RelateResult<'tcx, ty::FnSig<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.variadic != b.variadic { + return Err(ty::terr_variadic_mismatch( + expected_found(relation, &a.variadic, &b.variadic))); + } + + let inputs = try!(relate_arg_vecs(relation, + &a.inputs, + &b.inputs)); + + let output = try!(match (a.output, b.output) { + (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => + Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))), + (ty::FnDiverging, ty::FnDiverging) => + Ok(ty::FnDiverging), + (a, b) => + Err(ty::terr_convergence_mismatch( + expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), + }); + + return Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}); + } +} + +fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_args.len() != b_args.len() { + return Err(ty::terr_arg_count); + } + + a_args.iter() + .zip(b_args.iter()) + .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety { + fn relate(relation: &mut R, + a: &ast::Unsafety, + b: &ast::Unsafety) + -> RelateResult<'tcx, ast::Unsafety> + where R: TypeRelation<'a,'tcx> + { + if a != b { + Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi { + fn relate(relation: &mut R, + a: &abi::Abi, + b: &abi::Abi) + -> RelateResult<'tcx, abi::Abi> + where R: TypeRelation<'a,'tcx> + { + if a == b { + Ok(*a) + } else { + Err(ty::terr_abi_mismatch(expected_found(relation, a, b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionTy<'tcx>, + b: &ty::ProjectionTy<'tcx>) + -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.item_name != b.item_name { + Err(ty::terr_projection_name_mismatched( + expected_found(relation, &a.item_name, &b.item_name))) + } else { + let trait_ref = try!(relation.relate(&*a.trait_ref, &*b.trait_ref)); + Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>) + -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty)); + let ty = try!(relation.relate(&a.ty, &b.ty)); + Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec> { + fn relate(relation: &mut R, + a: &Vec>, + b: &Vec>) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> + { + // To be compatible, `a` and `b` must be for precisely the + // same set of traits and item names. We always require that + // projection bounds lists are sorted by trait-def-id and item-name, + // so we can just iterate through the lists pairwise, so long as they are the + // same length. + if a.len() != b.len() { + Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len()))) + } else { + a.iter() + .zip(b.iter()) + .map(|(a, b)| relation.relate(a, b)) + .collect() + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { + fn relate(relation: &mut R, + a: &ty::ExistentialBounds<'tcx>, + b: &ty::ExistentialBounds<'tcx>) + -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let r = try!(relation.relate_with_variance(ty::Contravariant, + &a.region_bound, + &b.region_bound)); + let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds)); + let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds)); + Ok(ty::ExistentialBounds { region_bound: r, + builtin_bounds: nb, + projection_bounds: pb }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds { + fn relate(relation: &mut R, + a: &ty::BuiltinBounds, + b: &ty::BuiltinBounds) + -> RelateResult<'tcx, ty::BuiltinBounds> + where R: TypeRelation<'a,'tcx> + { + // Two sets of builtin bounds are only relatable if they are + // precisely the same (but see the coercion code). + if a != b { + Err(ty::terr_builtin_bounds(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> { + fn relate(relation: &mut R, + a: &ty::TraitRef<'tcx>, + b: &ty::TraitRef<'tcx>) + -> RelateResult<'tcx, ty::TraitRef<'tcx>> + where R: TypeRelation<'a,'tcx> + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id))) + } else { + let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs)); + Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> { + fn relate(relation: &mut R, + a: &Ty<'tcx>, + b: &Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> + { + relation.tys(a, b) + } +} + +/// The main "type relation" routine. Note that this does not handle +/// inference artifacts, so you should filter those out before calling +/// it. +pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let tcx = relation.tcx(); + let a_sty = &a.sty; + let b_sty = &b.sty; + debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + match (a_sty, b_sty) { + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => + { + // The caller should handle these cases! + tcx.sess.bug("var types encountered in super_relate_tys") + } + + (&ty::ty_err, _) | (_, &ty::ty_err) => + { + Ok(tcx.types.err) + } + + (&ty::ty_char, _) | + (&ty::ty_bool, _) | + (&ty::ty_int(_), _) | + (&ty::ty_uint(_), _) | + (&ty::ty_float(_), _) | + (&ty::ty_str, _) + if a == b => + { + Ok(a) + } + + (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) + if a_p.idx == b_p.idx && a_p.space == b_p.space => + { + Ok(a) + } + + (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs)) + if a_id == b_id => + { + let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); + Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => + { + let principal = try!(relation.relate(&a_.principal, &b_.principal)); + let bounds = try!(relation.relate(&a_.bounds, &b_.bounds)); + Ok(ty::mk_trait(tcx, principal, bounds)) + } + + (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs)) + if a_id == b_id => + { + let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); + Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_closure(a_id, a_substs), + &ty::ty_closure(b_id, b_substs)) + if a_id == b_id => + { + // All ty_closure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let substs = try!(relate_substs(relation, None, a_substs, b_substs)); + Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => + { + let typ = try!(relation.relate(&a_inner, &b_inner)); + Ok(ty::mk_uniq(tcx, typ)) + } + + (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => + { + let mt = try!(relation.relate(a_mt, b_mt)); + Ok(ty::mk_ptr(tcx, mt)) + } + + (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => + { + let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r)); + let mt = try!(relation.relate(a_mt, b_mt)); + Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) + } + + (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => + { + let t = try!(relation.relate(&a_t, &b_t)); + if sz_a == sz_b { + Ok(ty::mk_vec(tcx, t, Some(sz_a))) + } else { + Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b))) + } + } + + (&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) => + { + let t = try!(relation.relate(&a_t, &b_t)); + Ok(ty::mk_vec(tcx, t, None)) + } + + (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => + { + if as_.len() == bs.len() { + let ts = try!(as_.iter() + .zip(bs.iter()) + .map(|(a, b)| relation.relate(a, b)) + .collect::>()); + Ok(ty::mk_tup(tcx, ts)) + } else if as_.len() != 0 && bs.len() != 0 { + Err(ty::terr_tuple_size( + expected_found(relation, &as_.len(), &bs.len()))) + } else { + Err(ty::terr_sorts(expected_found(relation, &a, &b))) + } + } + + (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty)) + if a_opt_def_id == b_opt_def_id => + { + let fty = try!(relation.relate(a_fty, b_fty)); + Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) + } + + (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => + { + let projection_ty = try!(relation.relate(a_data, b_data)); + Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) + } + + _ => + { + Err(ty::terr_sorts(expected_found(relation, &a, &b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { + fn relate(relation: &mut R, + a: &ty::Region, + b: &ty::Region) + -> RelateResult<'tcx, ty::Region> + where R: TypeRelation<'a,'tcx> + { + relation.regions(*a, *b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &ty::Binder, + b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where R: TypeRelation<'a,'tcx> + { + relation.binders(a, b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Rc, + b: &Rc) + -> RelateResult<'tcx, Rc> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Rc::new(try!(relation.relate(a, b)))) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Box, + b: &Box) + -> RelateResult<'tcx, Box> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Box::new(try!(relation.relate(a, b)))) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Error handling + +pub fn expected_found<'a,'tcx,R,T>(relation: &mut R, + a: &T, + b: &T) + -> ty::expected_found + where R: TypeRelation<'a,'tcx>, T: Clone +{ + expected_found_bool(relation.a_is_expected(), a, b) +} + +pub fn expected_found_bool(a_is_expected: bool, + a: &T, + b: &T) + -> ty::expected_found + where T: Clone +{ + let a = a.clone(); + let b = b.clone(); + if a_is_expected { + ty::expected_found {expected: a, found: b} + } else { + ty::expected_found {expected: b, found: a} + } +} + diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 452589a240754..91c320237d5ec 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1532,3 +1532,9 @@ impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { } } } + +impl<'tcx> Repr<'tcx> for ast::Unsafety { + fn repr(&self, _: &ctxt<'tcx>) -> String { + format!("{:?}", *self) + } +} diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index fcb0b9bdd3cfb..ac444478fcf16 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -22,7 +22,7 @@ use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; use rustc_typeck::middle::subst::Subst; use rustc_typeck::middle::ty::{self, Ty}; -use rustc_typeck::middle::infer::combine::Combine; +use rustc_typeck::middle::ty_relate::TypeRelation; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; @@ -350,21 +350,21 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn sub(&self) -> Sub<'a, 'tcx> { let trace = self.dummy_type_trace(); - Sub(self.infcx.combine_fields(true, trace)) + self.infcx.sub(true, trace) } pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); - Lub(self.infcx.combine_fields(true, trace)) + self.infcx.lub(true, trace) } pub fn glb(&self) -> Glb<'a, 'tcx> { let trace = self.dummy_type_trace(); - Glb(self.infcx.combine_fields(true, trace)) + self.infcx.glb(true, trace) } pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> { - match self.lub().tys(t1, t2) { + match self.lub().relate(&t1, &t2) { Ok(t) => t, Err(ref e) => panic!("unexpected error computing LUB: {}", ty::type_err_to_str(self.infcx.tcx, e)) @@ -374,7 +374,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `t1 <: t2` is true (this may register additional /// region checks). pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub().tys(t1, t2) { + match self.sub().relate(&t1, &t2) { Ok(_) => { } Err(ref e) => { panic!("unexpected error computing sub({},{}): {}", @@ -388,7 +388,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `t1 <: t2` is false (this may register additional /// region checks). pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub().tys(t1, t2) { + match self.sub().relate(&t1, &t2) { Err(_) => { } Ok(_) => { panic!("unexpected success computing sub({},{})", @@ -400,7 +400,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `LUB(t1,t2) == t_lub` pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { - match self.lub().tys(t1, t2) { + match self.lub().relate(&t1, &t2) { Ok(t) => { self.assert_eq(t, t_lub); } @@ -417,7 +417,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { self.ty_to_string(t1), self.ty_to_string(t2), self.ty_to_string(t_glb)); - match self.glb().tys(t1, t2) { + match self.glb().relate(&t1, &t2) { Err(e) => { panic!("unexpected error computing LUB: {:?}", e) } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 1ba0194f84ecb..ced6cec3ef0dc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,11 +62,11 @@ use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use middle::infer::{self, CombineResult, Coercion}; -use middle::infer::combine::Combine; +use middle::infer::{self, Coercion}; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{self, mt, Ty}; +use middle::ty_relate::RelateResult; use util::common::indent; use util::ppaux; use util::ppaux::Repr; @@ -78,7 +78,7 @@ struct Coerce<'a, 'tcx: 'a> { origin: infer::TypeOrigin, } -type CoerceResult<'tcx> = CombineResult<'tcx, Option>>; +type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -536,7 +536,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>) - -> CombineResult<'tcx, ()> { + -> RelateResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); let adjustment = try!(indent(|| { fcx.infcx().commit_if_ok(|_| { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index eaf07a3ef13a7..51d0c18872dc4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -30,7 +30,6 @@ use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn}; use middle::ty::ty_projection; use middle::ty; use CrateCtxt; -use middle::infer::combine::Combine; use middle::infer::InferCtxt; use middle::infer::new_infer_ctxt; use std::collections::HashSet; diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index ddc929017718d..2d87345db2245 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -23,10 +23,6 @@ pub fn main() { let f2: &Fat<[isize; 3]> = &f1; let f3: &Fat<[usize]> = f2; //~^ ERROR mismatched types - //~| expected `&Fat<[usize]>` - //~| found `&Fat<[isize; 3]>` - //~| expected usize - //~| found isize // With a trait. let f1 = Fat { ptr: Foo }; From cead47ca53a2c6bb0f774264131dccbc0936d90b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 20 Mar 2015 08:17:09 -0400 Subject: [PATCH 14/28] Add a "match" relation that can be used to make recursion check during trait matching more tailored. We now detect recursion where the obligations "match" -- meaning basically that they are the same for some substitution of any unbound type variables. --- src/librustc/lib.rs | 1 + src/librustc/middle/traits/select.rs | 14 +++- src/librustc/middle/ty_match.rs | 95 ++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/librustc/middle/ty_match.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8a4790c17a405..8f0ccbd446110 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -122,6 +122,7 @@ pub mod middle { pub mod traits; pub mod ty; pub mod ty_fold; + pub mod ty_match; pub mod ty_relate; pub mod ty_walk; pub mod weak_lang_items; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 8004cc37ccfd6..169e06a959419 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -38,6 +38,8 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; +use middle::ty_match; +use middle::ty_relate::TypeRelation; use std::cell::RefCell; use std::rc::Rc; use syntax::{abi, ast}; @@ -472,7 +474,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) + |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref, + &prev.fresh_trait_ref))) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", stack.fresh_trait_ref.repr(self.tcx())); @@ -2475,6 +2478,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Miscellany + fn match_fresh_trait_refs(&self, + previous: &ty::PolyTraitRef<'tcx>, + current: &ty::PolyTraitRef<'tcx>) + -> bool + { + let mut matcher = ty_match::Match::new(self.tcx()); + matcher.relate(previous, current).is_ok() + } + fn push_stack<'o,'s:'o>(&mut self, previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>, obligation: &'o TraitObligation<'tcx>) diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs new file mode 100644 index 0000000000000..bb00fadc39c95 --- /dev/null +++ b/src/librustc/middle/ty_match.rs @@ -0,0 +1,95 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::ty::{self, Ty}; +use middle::ty_relate::{self, Relate, TypeRelation, RelateResult}; +use util::ppaux::Repr; + +/// A type "A" *matches* "B" if the fresh types in B could be +/// substituted with values so as to make it equal to A. Matching is +/// intended to be used only on freshened types, and it basically +/// indicates if the non-freshened versions of A and B could have been +/// unified. +/// +/// It is only an approximation. If it yields false, unification would +/// definitely fail, but a true result doesn't mean unification would +/// succeed. This is because we don't track the "side-constraints" on +/// type variables, nor do we track if the same freshened type appears +/// more than once. To some extent these approximations could be +/// fixed, given effort. +/// +/// Like subtyping, matching is really a binary relation, so the only +/// important thing about the result is Ok/Err. Also, matching never +/// affects any type variables or unification state. +pub struct Match<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx> +} + +impl<'a, 'tcx> Match<'a, 'tcx> { + pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> { + Match { tcx: tcx } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { + fn tag(&self) -> &'static str { "Match" } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn a_is_expected(&self) -> bool { true } // irrelevant + + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.tcx()), + b.repr(self.tcx())); + Ok(a) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({}, {})", self.tag(), + a.repr(self.tcx()), b.repr(self.tcx())); + if a == b { return Ok(a); } + + match (&a.sty, &b.sty) { + (_, &ty::ty_infer(ty::FreshTy(_))) | + (_, &ty::ty_infer(ty::FreshIntTy(_))) => { + Ok(a) + } + + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => { + Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b))) + } + + (&ty::ty_err, _) | (_, &ty::ty_err) => { + Ok(self.tcx().types.err) + } + + _ => { + ty_relate::super_relate_tys(self, a, b) + } + } + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder())))) + } +} From cdb10b884b3975dd897096e052f386f55cf0f4c9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Mar 2015 04:38:43 -0400 Subject: [PATCH 15/28] A very simple hack to force an autoderef if the callee has type `&mut F`, so that if we have `x: &mut FnMut()`, then `x()` is translated to `FnMut::call_mut(&mut *x, ())` rather than `&mut x`. The latter would require `mut x: &mut FnMut()`, which is really a lot of mut. (Actually, the `mut` is normally required except for the special case of a `&mut F` reference, because that's the one case where we distinguish a unique path like `x` from a mutable path.) --- src/librustc_typeck/check/callee.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 31ac0a57ba0e1..3f9c14e0afe39 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -83,9 +83,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - try_overloaded_call_step(fcx, call_expr, callee_expr, - adj_ty, autoderefref) + try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx) }); match result { @@ -119,13 +117,15 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { - debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", + debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})", call_expr.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()), - autoderefref.repr(fcx.tcx())); + autoderefs); + + let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None }; // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { @@ -161,6 +161,18 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } + // Hack: we know that there are traits implementing Fn for &F + // where F:Fn and so forth. In the particular case of types + // like `x: &mut FnMut()`, if there is a call `x()`, we would + // normally translate to `FnMut::call_mut(&mut x, ())`, but + // that winds up requiring `mut x: &mut FnMut()`. A little + // over the top. The simplest fix by far is to just ignore + // this case and deref again, so we wind up with + // `FnMut::call_mut(&mut *x, ())`. + ty::ty_rptr(..) if autoderefs == 0 => { + return None; + } + _ => {} } From 27b7841bb1261fb2d94a0ed6f2ec0a146a44783d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 20 Mar 2015 08:18:04 -0400 Subject: [PATCH 16/28] Add blanket impls for references to the `Fn` traits. --- src/libcore/ops.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 862eb16d0bfb3..861892f026168 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1142,3 +1142,52 @@ pub trait FnOnce { /// This is called when the call operator is used. extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } + +#[cfg(not(stage0))] +mod impls { + use marker::Sized; + use super::{Fn, FnMut, FnOnce}; + + impl<'a,A,F:?Sized> Fn for &'a F + where F : Fn + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a F + where F : Fn + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a F + where F : Fn + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a mut F + where F : FnMut + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a mut F + where F : FnMut + { + type Output = F::Output; + extern "rust-call" fn call_once(mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } +} From 11111bb6b7889ce45770a6ffe46c75a2690c387f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Mar 2015 12:09:24 -0400 Subject: [PATCH 17/28] Add tests for blanket impls. --- .../unboxed-closures-blanket-fn-mut.rs | 37 +++++++++++++++++++ .../run-pass/unboxed-closures-blanket-fn.rs | 37 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/test/run-pass/unboxed-closures-blanket-fn-mut.rs create mode 100644 src/test/run-pass/unboxed-closures-blanket-fn.rs diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs new file mode 100644 index 0000000000000..37dccca1e2245 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you can supply `&F` where `F: FnMut()`. + +// pretty-expanded FIXME #23616 + +#![feature(lang_items, unboxed_closures)] + +fn a i32>(mut f: F) -> i32 { + f() +} + +fn b(f: &mut FnMut() -> i32) -> i32 { + a(f) +} + +fn c i32>(f: &mut F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&mut || 22); + assert_eq!(x, 22); + + let x = c(&mut || 22); + assert_eq!(x, 22); +} diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs new file mode 100644 index 0000000000000..0f93966077bc3 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you can supply `&F` where `F: Fn()`. + +// pretty-expanded FIXME #23616 + +#![feature(lang_items, unboxed_closures)] + +fn a i32>(f: F) -> i32 { + f() +} + +fn b(f: &Fn() -> i32) -> i32 { + a(f) +} + +fn c i32>(f: &F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&|| 22); + assert_eq!(x, 22); + + let x = c(&|| 22); + assert_eq!(x, 22); +} From a5479622eac34ee38e07763a02ac1f9ec118a66b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 24 Mar 2015 14:52:55 +1300 Subject: [PATCH 18/28] Pretty print ids for assoc items --- src/librustc/middle/dataflow.rs | 2 +- src/librustc_driver/pretty.rs | 4 ++++ src/libsyntax/print/pprust.rs | 19 ++++++++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index a112ce6bd287c..7e436d95192f5 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O pprust::NodeIdent(_) | pprust::NodeName(_) => 0, pprust::NodeExpr(expr) => expr.id, pprust::NodeBlock(blk) => blk.id, - pprust::NodeItem(_) => 0, + pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0, pprust::NodePat(pat) => pat.id }; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 9e693a64ef0a2..827310e04dd41 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -226,6 +226,10 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { try!(pp::space(&mut s.s)); s.synth_comment(item.id.to_string()) } + pprust::NodeSubItem(id) => { + try!(pp::space(&mut s.s)); + s.synth_comment(id.to_string()) + } pprust::NodeBlock(blk) => { try!(pp::space(&mut s.s)); s.synth_comment(format!("block {}", blk.id)) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index da1b7a7bdde50..c2f323f98afc5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -37,6 +37,7 @@ pub enum AnnNode<'a> { NodeName(&'a ast::Name), NodeBlock(&'a ast::Block), NodeItem(&'a ast::Item), + NodeSubItem(ast::NodeId), NodeExpr(&'a ast::Expr), NodePat(&'a ast::Pat), } @@ -1264,6 +1265,7 @@ impl<'a> State<'a> { pub fn print_trait_item(&mut self, ti: &ast::TraitItem) -> io::Result<()> { + try!(self.ann.pre(self, NodeSubItem(ti.id))); try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(ti.span.lo)); try!(self.print_outer_attributes(&ti.attrs)); @@ -1275,19 +1277,21 @@ impl<'a> State<'a> { try!(self.print_method_sig(ti.ident, sig, ast::Inherited)); if let Some(ref body) = *body { try!(self.nbsp()); - self.print_block_with_attrs(body, &ti.attrs) + try!(self.print_block_with_attrs(body, &ti.attrs)); } else { - word(&mut self.s, ";") + try!(word(&mut self.s, ";")); } } ast::TypeTraitItem(ref bounds, ref default) => { - self.print_associated_type(ti.ident, Some(bounds), - default.as_ref().map(|ty| &**ty)) + try!(self.print_associated_type(ti.ident, Some(bounds), + default.as_ref().map(|ty| &**ty))); } } + self.ann.post(self, NodeSubItem(ti.id)) } pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> { + try!(self.ann.pre(self, NodeSubItem(ii.id))); try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(ii.span.lo)); try!(self.print_outer_attributes(&ii.attrs)); @@ -1296,10 +1300,10 @@ impl<'a> State<'a> { try!(self.head("")); try!(self.print_method_sig(ii.ident, sig, ii.vis)); try!(self.nbsp()); - self.print_block_with_attrs(body, &ii.attrs) + try!(self.print_block_with_attrs(body, &ii.attrs)); } ast::TypeImplItem(ref ty) => { - self.print_associated_type(ii.ident, None, Some(ty)) + try!(self.print_associated_type(ii.ident, None, Some(ty))); } ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), ..}) => { @@ -1311,9 +1315,10 @@ impl<'a> State<'a> { try!(self.print_tts(&tts[..])); try!(self.pclose()); try!(word(&mut self.s, ";")); - self.end() + try!(self.end()) } } + self.ann.post(self, NodeSubItem(ii.id)) } pub fn print_outer_attributes(&mut self, From bfc2f5de85c86b7d60a26d16b9991d9763b4c07e Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 31 Mar 2015 20:18:32 -0400 Subject: [PATCH 19/28] =?UTF-8?q?Improvements=20to=20PhantomData's=20do?= =?UTF-8?q?cs=20=F0=9F=91=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #22914 --- src/libcore/marker.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3f4b39da4b3bb..a07b37a802629 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -346,17 +346,16 @@ impl MarkerTrait for T { } #[stable(feature = "rust1", since = "1.0.0")] pub trait PhantomFn { } -/// `PhantomData` is a way to tell the compiler about fake fields. -/// Phantom data is required whenever type parameters are not used. -/// The idea is that if the compiler encounters a `PhantomData` -/// instance, it will behave *as if* an instance of the type `T` were -/// present for the purpose of various automatic analyses. +/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, +/// even though it does not. This allows you to inform the compiler about certain safety properties +/// of your code. +/// +/// Though they both have scary names, `PhantomData` and "phantom types" are unrelated. 👻👻👻 /// /// # Examples /// /// When handling external resources over a foreign function interface, `PhantomData` can -/// prevent mismatches by enforcing types in the method implementations, although the struct -/// doesn't actually contain values of the resource type. +/// prevent mismatches by enforcing types in the method implementations: /// /// ``` /// # trait ResType { fn foo(&self); }; @@ -397,11 +396,6 @@ pub trait PhantomFn { } /// commonly necessary if the structure is using an unsafe pointer /// like `*mut T` whose referent may be dropped when the type is /// dropped, as a `*mut T` is otherwise not treated as owned. -/// -/// FIXME. Better documentation and examples of common patterns needed -/// here! For now, please see [RFC 738][738] for more information. -/// -/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md #[lang="phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; From 0dd0925f5777122460ee84acf0b6dae76b58b25a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 30 Mar 2015 12:21:20 +1300 Subject: [PATCH 20/28] Tidying up and reformatting --- src/librustc/middle/def.rs | 13 ++- src/librustc/middle/privacy.rs | 6 +- src/librustc_resolve/lib.rs | 94 +++++++++---------- src/librustc_typeck/astconv.rs | 149 +++++++++++++++++++------------ src/librustc_typeck/check/mod.rs | 8 +- 5 files changed, 154 insertions(+), 116 deletions(-) diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 1a054c0f464aa..c60bb229be142 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -65,7 +65,7 @@ pub enum Def { /// ::AssocX::AssocY::MethodOrAssocType /// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ /// base_def depth = 2 -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct PathResolution { pub base_def: Def, pub last_private: LastPrivate, @@ -85,6 +85,17 @@ impl PathResolution { pub fn def_id(&self) -> ast::DefId { self.full_def().def_id() } + + pub fn new(base_def: Def, + last_private: LastPrivate, + depth: usize) + -> PathResolution { + PathResolution { + base_def: base_def, + last_private: last_private, + depth: depth, + } + } } // Definition mapping diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 3a253735f925b..d8efb5655aaab 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -32,7 +32,7 @@ pub type ExternalExports = DefIdSet; /// reexporting a public struct doesn't inline the doc). pub type PublicItems = NodeSet; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum LastPrivate { LastMod(PrivateDep), // `use` directives (imports) can refer to two separate definitions in the @@ -46,14 +46,14 @@ pub enum LastPrivate { type_used: ImportUse}, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum PrivateDep { AllPublic, DependsOn(ast::DefId), } // How an import is used. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ImportUse { Unused, // The import is not used. Used, // The import is used. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ff635a6c46b22..ece83b578d257 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -162,9 +162,12 @@ impl NamespaceResult { } enum NameDefinition { - NoNameDefinition, //< The name was unbound. - ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child. - ImportNameDefinition(Def, LastPrivate) //< The name identifies an import. + // The name was unbound. + NoNameDefinition, + // The name identifies an immediate child. + ChildNameDefinition(Def, LastPrivate), + // The name identifies an import. + ImportNameDefinition(Def, LastPrivate), } impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { @@ -795,11 +798,6 @@ pub struct Resolver<'a, 'tcx:'a> { // The current self type if inside an impl (used for better errors). current_self_type: Option, - // The ident for the keyword "self". - self_name: Name, - // The ident for the non-keyword "Self". - type_self_name: Name, - // The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, @@ -869,9 +867,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { current_trait_ref: None, current_self_type: None, - self_name: special_names::self_, - type_self_name: special_names::type_self, - primitive_type_table: PrimitiveTypeTable::new(), def_map: RefCell::new(NodeMap()), @@ -1822,7 +1817,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut self_type_rib = Rib::new(ItemRibKind); // plain insert (no renaming, types are not currently hygienic....) - let name = self.type_self_name; + let name = special_names::type_self; self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id))); self.type_ribs.push(self_type_rib); @@ -2047,8 +2042,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, - f: F) -> T where - F: FnOnce(&mut Resolver) -> T, + f: F) + -> T + where F: FnOnce(&mut Resolver) -> T, { let mut new_val = None; if let Some(trait_ref) = opt_trait_ref { @@ -2585,11 +2581,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = path.span; let segments = &path.segments[..path.segments.len()-path_depth]; - let mk_res = |(def, lp)| PathResolution { - base_def: def, - last_private: lp, - depth: path_depth - }; + let mk_res = |(def, lp)| PathResolution::new(def, lp, path_depth); if path.global { let def = self.resolve_crate_relative_path(span, segments, namespace); @@ -2603,25 +2595,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs, span); - if segments.len() > 1 { - let def = self.resolve_module_relative_path(span, segments, namespace); - match (def, unqualified_def) { - (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { - self.session - .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, - id, span, - "unnecessary qualification".to_string()); - } - _ => () - } + if segments.len() <= 1 { + return unqualified_def.map(mk_res); + } - def.map(mk_res) - } else { - unqualified_def.map(mk_res) + let def = self.resolve_module_relative_path(span, segments, namespace); + match (def, unqualified_def) { + (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { + self.session + .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, + id, span, + "unnecessary qualification".to_string()); + } + _ => {} } + + def.map(mk_res) } - // resolve a single identifier (used as a varref) + // Resolve a single identifier. fn resolve_identifier(&mut self, identifier: Ident, namespace: Namespace, @@ -2662,8 +2654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match child_name_bindings.def_for_namespace(namespace) { Some(def) => { // Found it. Stop the search here. - let p = child_name_bindings.defined_in_public_namespace( - namespace); + let p = child_name_bindings.defined_in_public_namespace(namespace); let lp = if p {LastMod(AllPublic)} else { LastMod(DependsOn(def.def_id())) }; @@ -2734,8 +2725,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let containing_module; let last_private; - let module = self.current_module.clone(); - match self.resolve_module_path(module, + let current_module = self.current_module.clone(); + match self.resolve_module_path(current_module, &module_path[..], UseLexicalScope, span, @@ -2858,8 +2849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match search_result { Some(DlDef(def)) => { - debug!("(resolving path in local ribs) resolved `{}` to \ - local: {:?}", + debug!("(resolving path in local ribs) resolved `{}` to local: {:?}", token::get_ident(ident), def); Some(def) @@ -2904,15 +2894,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { panic!("unexpected indeterminate result"); } Failed(err) => { - match err { - Some((span, msg)) => - self.resolve_error(span, &format!("failed to resolve. {}", - msg)), - None => () - } - debug!("(resolving item path by identifier in lexical scope) \ failed to resolve {}", token::get_name(name)); + + if let Some((span, msg)) = err { + self.resolve_error(span, &format!("failed to resolve. {}", msg)) + } + return None; } } @@ -2964,10 +2952,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } else { match this.resolve_module_path(root, - &name_path[..], - UseLexicalScope, - span, - PathSearch) { + &name_path[..], + UseLexicalScope, + span, + PathSearch) { Success((module, _)) => Some(module), _ => None } @@ -3203,8 +3191,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false // Stop advancing }); - if method_scope && &token::get_name(self.self_name)[..] - == path_name { + if method_scope && + &token::get_name(special_names::self_)[..] == path_name { self.resolve_error( expr.span, "`self` is not available \ diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0d6ca7430d38e..939142cff1c32 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -140,13 +140,7 @@ pub trait AstConv<'tcx> { span: Span, _trait_ref: Rc>, _item_name: ast::Name) - -> Ty<'tcx> - { - span_err!(self.tcx().sess, span, E0213, - "associated types are not accepted in this context"); - - self.tcx().types.err - } + -> Ty<'tcx>; } pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) @@ -924,9 +918,12 @@ fn ast_path_to_ty<'tcx>( } }; - let substs = ast_path_substs_for_ty(this, rscope, - span, param_mode, - &generics, item_segment); + let substs = ast_path_substs_for_ty(this, + rscope, + span, + param_mode, + &generics, + item_segment); // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == this.tcx().lang_items.owned_box() { @@ -1044,6 +1041,12 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, type_str, trait_str, name); } +// Create a type from a a path to an associated type. +// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C +// and item_segment is the path segment for D. We return a type and a def for +// the whole path. +// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type +// parameter or Self. fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, span: Span, ty: Ty<'tcx>, @@ -1052,35 +1055,43 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, -> (Ty<'tcx>, def::Def) { let tcx = this.tcx(); - check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); let assoc_name = item_segment.identifier.name; - let is_param = match (&ty.sty, ty_path_def) { - (&ty::ty_param(_), def::DefTyParam(..)) | - (&ty::ty_param(_), def::DefSelfTy(_)) => true, - _ => false - }; + debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name)); - let ty_param_node_id = if is_param { - ty_path_def.local_node_id() - } else { - report_ambiguous_associated_type( - tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name)); - return (tcx.types.err, ty_path_def); - }; + check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); + + // Check that the path prefix given by ty/ty_path_def is a type parameter/Self. + match (&ty.sty, ty_path_def) { + (&ty::ty_param(_), def::DefTyParam(..)) | + (&ty::ty_param(_), def::DefSelfTy(_)) => {} + _ => { + report_ambiguous_associated_type(tcx, + span, + &ty.user_string(tcx), + "Trait", + &token::get_name(assoc_name)); + return (tcx.types.err, ty_path_def); + } + } + let ty_param_node_id = ty_path_def.local_node_id(); let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { Ok(v) => v, - Err(ErrorReported) => { return (tcx.types.err, ty_path_def); } + Err(ErrorReported) => { + return (tcx.types.err, ty_path_def); + } }; - // ensure the super predicates and stop if we encountered an error + // Ensure the super predicates and stop if we encountered an error. if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { return (this.tcx().types.err, ty_path_def); } + // Check that there is exactly one way to find an associated type with the + // correct name. let mut suitable_bounds: Vec<_> = traits::transitive_bounds(tcx, &bounds) .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) @@ -1118,7 +1129,8 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, // by type collection, which may be in progress at this point. match this.tcx().map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { - let item = trait_items.iter().find(|i| i.ident.name == assoc_name) + let item = trait_items.iter() + .find(|i| i.ident.name == assoc_name) .expect("missing associated type"); ast_util::local_def(item.id) } @@ -1129,6 +1141,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; + (ty, def::DefAssociatedTy(trait_did, item_did)) } @@ -1150,8 +1163,11 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, ty } else { let path_str = ty::item_path_str(tcx, trait_def_id); - report_ambiguous_associated_type( - tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier)); + report_ambiguous_associated_type(tcx, + span, + "Type", + &path_str, + &token::get_ident(item_segment.identifier)); return tcx.types.err; }; @@ -1204,13 +1220,15 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } +// Note that both base_segments and assoc_segments may be empty, although not at +// the same time. pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, - def: &mut def::Def, + def: &def::Def, opt_self_ty: Option>, - segments: &[ast::PathSegment], + base_segments: &[ast::PathSegment], assoc_segments: &[ast::PathSegment]) -> Ty<'tcx> { let tcx = this.tcx(); @@ -1226,52 +1244,64 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, span, param_mode, trait_def_id, - segments.last().unwrap(), + base_segments.last().unwrap(), &mut projection_bounds); - check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); - trait_ref_to_object_type(this, rscope, span, trait_ref, - projection_bounds, &[]) + check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); + trait_ref_to_object_type(this, + rscope, + span, + trait_ref, + projection_bounds, + &[]) } def::DefTy(did, _) | def::DefStruct(did) => { - check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); + check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); ast_path_to_ty(this, rscope, span, param_mode, did, - segments.last().unwrap()) + base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { - check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_param(tcx, space, index, name) } def::DefSelfTy(_) => { - // n.b.: resolve guarantees that the this type only appears in a + // N.b.: resolve guarantees that the this type only appears in a // trait, which we rely upon in various places when creating - // substs - check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + // substs. + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_self_type(tcx) } def::DefAssociatedTy(trait_did, _) => { - check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS); - qpath_to_ty(this, rscope, span, param_mode, - opt_self_ty, trait_did, - &segments[segments.len()-2], - segments.last().unwrap()) + check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS); + qpath_to_ty(this, + rscope, + span, + param_mode, + opt_self_ty, + trait_did, + &base_segments[base_segments.len()-2], + base_segments.last().unwrap()) } def::DefMod(id) => { // Used as sentinel by callers to indicate the `::A::B::C` form. // FIXME(#22519) This part of the resolution logic should be // avoided entirely for that form, once we stop needed a Def // for `associated_path_def_to_ty`. - if segments.is_empty() { - opt_self_ty.expect("missing T in ::a::b::c") - } else { - span_err!(tcx.sess, span, E0247, "found module name used as a type: {}", + + if !base_segments.is_empty() { + span_err!(tcx.sess, + span, + E0247, + "found module name used as a type: {}", tcx.map.node_to_string(id.node)); return this.tcx().types.err; } + + opt_self_ty.expect("missing T in ::a::b::c") } def::DefPrimTy(prim_ty) => { - prim_ty_to_ty(tcx, segments, prim_ty) + prim_ty_to_ty(tcx, base_segments, prim_ty) } _ => { span_err!(tcx.sess, span, E0248, @@ -1282,15 +1312,19 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // If any associated type segments remain, attempt to resolve them. let mut ty = base_ty; + let mut def = *def; for segment in assoc_segments { if ty.sty == ty::ty_err { break; } // This is pretty bad (it will fail except for T::A and Self::A). - let (a_ty, a_def) = associated_path_def_to_ty(this, span, - ty, *def, segment); + let (a_ty, a_def) = associated_path_def_to_ty(this, + span, + ty, + def, + segment); ty = a_ty; - *def = a_def; + def = a_def; } ty } @@ -1378,13 +1412,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, tcx.sess.span_bug(ast_ty.span, &format!("unbound path {}", ast_ty.repr(tcx))) }; - let mut def = path_res.base_def; + let def = path_res.base_def; let base_ty_end = path.segments.len() - path_res.depth; let opt_self_ty = maybe_qself.as_ref().map(|qself| { ast_ty_to_ty(this, rscope, &qself.ty) }); - let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span, - PathParamMode::Explicit, &mut def, + let ty = finish_resolving_def_to_ty(this, + rscope, + ast_ty.span, + PathParamMode::Explicit, + &def, opt_self_ty, &path.segments[..base_ty_end], &path.segments[base_ty_end..]); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16501ec280791..3854d85181039 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3329,7 +3329,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, &format!("unbound path {}", expr.repr(tcx))) }; - let mut def = path_res.base_def; + let def = path_res.base_def; if path_res.depth == 0 { let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, def); @@ -3339,9 +3339,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } else { let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; - let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span, + let ty = astconv::finish_resolving_def_to_ty(fcx, + fcx, + expr.span, PathParamMode::Optional, - &mut def, + &def, opt_self_ty, &ty_segments[..base_ty_end], &ty_segments[base_ty_end..]); From 39aa668a01fb671cff382a8237ec3993c9cc4c33 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 29 Mar 2015 17:38:05 -0400 Subject: [PATCH 21/28] Added Arc::try_unique --- src/liballoc/arc.rs | 56 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 9b37ddc7ab533..5dcdddfafa466 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -242,6 +242,38 @@ pub fn weak_count(this: &Arc) -> usize { this.inner().weak.load(SeqCst) - #[unstable(feature = "alloc")] pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst) } + +/// Try accessing a mutable reference to the contents behind an unique `Arc`. +/// +/// The access is granted only if this is the only reference to the object. +/// Otherwise, `None` is returned. +/// +/// # Examples +/// +/// ``` +/// # #![feature(alloc)] +/// use std::alloc::arc; +/// +/// let mut four = arc::Arc::new(4); +/// +/// arc::unique(&mut four).map(|num| *num = 5); +/// ``` +#[inline] +#[unstable(feature = "alloc")] +pub fn unique(this: &mut Arc) -> Option<&mut T> { + if strong_count(this) == 1 && weak_count(this) == 0 { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + let inner = unsafe { &mut **this._ptr }; + Some(&mut inner.data) + }else { + None + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { /// Makes a clone of the `Arc`. @@ -312,11 +344,8 @@ impl Arc { self.inner().weak.load(SeqCst) != 1 { *self = Arc::new((**self).clone()) } - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. + // As with `unique()`, the unsafety is ok because our reference was + // either unique to begin with, or became one upon cloning the contents. let inner = unsafe { &mut **self._ptr }; &mut inner.data } @@ -659,7 +688,7 @@ mod tests { use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::thread; use std::vec::Vec; - use super::{Arc, Weak, weak_count, strong_count}; + use super::{Arc, Weak, weak_count, strong_count, unique}; use std::sync::Mutex; struct Canary(*mut atomic::AtomicUsize); @@ -695,6 +724,21 @@ mod tests { assert_eq!((*arc_v)[4], 5); } + #[test] + fn test_arc_unique() { + let mut x = Arc::new(10); + assert!(unique(&mut x).is_some()); + { + let y = x.clone(); + assert!(unique(&mut x).is_none()); + } + { + let z = x.downgrade(); + assert!(unique(&mut x).is_none()); + } + assert!(unique(&mut x).is_some()); + } + #[test] fn test_cowarc_clone_make_unique() { let mut cow0 = Arc::new(75); From 8ded1562658915f6160f5b83e5036c6900c139e3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 1 Apr 2015 01:11:38 -0400 Subject: [PATCH 22/28] Add examples + documentation for std::path --- src/libstd/path.rs | 213 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 58d3ae9f7cfab..df0b3842b7a34 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -344,6 +344,15 @@ impl<'a> Prefix<'a> { /// Determine whether the character is one of the permitted path /// separators for the current platform. +/// +/// # Examples +/// +/// ``` +/// use std::path; +/// +/// assert!(path::is_separator('/')); +/// assert!(!path::is_separator('❤')); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_separator(c: char) -> bool { use ascii::*; @@ -540,6 +549,18 @@ impl<'a> AsRef for Component<'a> { /// /// See the module documentation for an in-depth explanation of components and /// their role in the API. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo/bar.txt"); +/// +/// for component in path.components() { +/// println!("{:?}", component); +/// } +/// ``` #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -610,6 +631,16 @@ impl<'a> Components<'a> { } /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo/bar.txt"); + /// + /// println!("{:?}", path.components().as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); @@ -1207,12 +1238,28 @@ impl Path { /// Directly wrap a string slice as a `Path` slice. /// /// This is a cost-free conversion. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// Path::new("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &Path { unsafe { mem::transmute(s.as_ref()) } } /// Yield the underlying `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let os_str = Path::new("foo.txt").as_os_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { &self.inner @@ -1221,6 +1268,14 @@ impl Path { /// Yield a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() @@ -1229,12 +1284,28 @@ impl Path { /// Convert a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_string_lossy(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow { self.inner.to_string_lossy() } /// Convert a `Path` to an owned `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_path_buf(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) @@ -1248,6 +1319,14 @@ impl Path { /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In /// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert_eq!(false, Path::new("foo.txt").is_absolute()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_absolute(&self) -> bool { self.has_root() && @@ -1255,6 +1334,14 @@ impl Path { } /// A path is *relative* if it is not absolute. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("foo.txt").is_relative()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1278,6 +1365,14 @@ impl Path { /// * has no prefix and begins with a separator, e.g. `\\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("/etc/passwd").has_root()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn has_root(&self) -> bool { self.components().has_root() @@ -1294,8 +1389,11 @@ impl Path { /// /// let path = Path::new("/foo/bar"); /// let foo = path.parent().unwrap(); + /// /// assert!(foo == Path::new("/foo")); + /// /// let root = foo.parent().unwrap(); + /// /// assert!(root == Path::new("/")); /// assert!(root.parent() == None); /// ``` @@ -1315,6 +1413,17 @@ impl Path { /// /// If the path terminates in `.`, `..`, or consists solely or a root of /// prefix, `file_name` will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("hello_world.rs"); + /// let filename = "hello_world.rs"; + /// + /// assert_eq!(filename, path.file_name().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { self.components().next_back().and_then(|p| match p { @@ -1334,12 +1443,32 @@ impl Path { } /// Determines whether `base` is a prefix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.starts_with("/etc")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with>(&self, base: P) -> bool { iter_after(self.components(), base.as_ref().components()).is_some() } /// Determines whether `child` is a suffix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.ends_with("passwd")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ends_with>(&self, child: P) -> bool { iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() @@ -1353,6 +1482,16 @@ impl Path { /// * The entire file name if there is no embedded `.`; /// * The entire file name if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name before the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("foo", path.file_stem().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_stem(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) @@ -1366,6 +1505,16 @@ impl Path { /// * None, if there is no embedded `.`; /// * None, if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("rs", path.extension().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn extension(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after)) @@ -1374,6 +1523,16 @@ impl Path { /// Creates an owned `PathBuf` with `path` adjoined to `self`. /// /// See `PathBuf::push` for more details on what it means to adjoin a path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp"); + /// + /// let new_path = path.join("foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn join>(&self, path: P) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1384,6 +1543,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given file name. /// /// See `PathBuf::set_file_name` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_file_name("bar.rs"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name>(&self, file_name: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1394,6 +1563,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given extension. /// /// See `PathBuf::set_extension` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_extension("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1402,6 +1581,18 @@ impl Path { } /// Produce an iterator over the components of the path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.components() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1415,6 +1606,18 @@ impl Path { } /// Produce an iterator over the path's components viewed as `OsStr` slices. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.iter() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { Iter { inner: self.components() } @@ -1422,6 +1625,16 @@ impl Path { /// Returns an object that implements `Display` for safely printing paths /// that may contain non-Unicode data. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// println!("{}", path.display()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn display(&self) -> Display { Display { path: self } From 4b6248a80658ec2e3b1552441f57ebc4b1f06448 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 31 Mar 2015 21:22:17 -0400 Subject: [PATCH 23/28] Simplify `match` branches in iter.rs example --- src/libcore/iter.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 2d69eeb9fa962..42e90ec34db7c 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -45,10 +45,8 @@ //! let mut it = values.into_iter(); //! loop { //! match it.next() { -//! Some(x) => { -//! println!("{}", x); -//! } -//! None => { break } +//! Some(x) => println!("{}", x), +//! None => break, //! } //! } //! ``` From 03d3ba7667ed9599f46b742ac314a43297d76b19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:46:34 -0400 Subject: [PATCH 24/28] Implement the changes to coherence such that we consider a type to be local only if matches `FUNDAMENTAL(LocalType)`, where `FUNDAMENTAL` includes `&T` and types marked as fundamental (which includes `Box`). Also apply these tests to negative reasoning. --- src/librustc/middle/traits/coherence.rs | 203 +++++++++++++++++------- src/librustc/middle/traits/select.rs | 103 ++++++++---- src/librustc/middle/traits/util.rs | 38 ++++- src/librustc/middle/ty.rs | 27 ++-- src/librustc/middle/ty_walk.rs | 117 +++++++------- src/librustc/util/ppaux.rs | 8 +- src/libsyntax/feature_gate.rs | 6 + 7 files changed, 337 insertions(+), 165 deletions(-) diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 11d073ce72e73..411be28b89695 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,15 +17,17 @@ use super::PredicateObligation; use super::project; use super::util; -use middle::subst::{Subst, TypeSpace}; +use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, ToPolyTraitRef, Ty}; use middle::infer::{self, InferCtxt}; -use std::collections::HashSet; use std::rc::Rc; use syntax::ast; -use syntax::codemap::DUMMY_SP; +use syntax::codemap::{DUMMY_SP, Span}; use util::ppaux::Repr; +#[derive(Copy)] +struct ParamIsLocal(bool); + /// True if there exist types that satisfy both of the two given impls. pub fn overlapping_impls(infcx: &InferCtxt, impl1_def_id: ast::DefId, @@ -56,10 +58,16 @@ fn overlap(selcx: &mut SelectionContext, a_def_id.repr(selcx.tcx()), b_def_id.repr(selcx.tcx())); - let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); - let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); + let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, + a_def_id, + util::free_substs_for_impl); + + let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, + b_def_id, + util::fresh_type_vars_for_impl); debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx())); + debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx())); // Does `a <: b` hold? If not, no overlap. @@ -74,28 +82,68 @@ fn overlap(selcx: &mut SelectionContext, debug!("overlap: subtraitref check succeeded"); // Are any of the obligations unsatisfiable? If so, no overlap. + let tcx = selcx.tcx(); + let infcx = selcx.infcx(); let opt_failing_obligation = a_obligations.iter() .chain(b_obligations.iter()) + .map(|o| infcx.resolve_type_vars_if_possible(o)) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx())); - return false; + debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx)); + return false } true } +pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool +{ + debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx)); + + // if the orphan rules pass, that means that no ancestor crate can + // impl this, so it's up to us. + if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() { + debug!("trait_ref_is_knowable: orphan check passed"); + return true; + } + + // if the trait is not marked fundamental, then it's always possible that + // an ancestor crate will impl this in the future, if they haven't + // already + if + trait_ref.def_id.krate != ast::LOCAL_CRATE && + !ty::has_attr(tcx, trait_ref.def_id, "fundamental") + { + debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); + return false; + } + + // find out when some downstream (or cousin) crate could impl this + // trait-ref, presuming that all the parameters were instantiated + // with downstream types. If not, then it could only be + // implemented by an upstream crate, which means that the impl + // must be visible to us, and -- since the trait is fundamental + // -- we can test. + orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err() +} + +type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx>; + /// Instantiate fresh variables for all bound parameters of the impl /// and return the impl trait ref with those variables substituted. fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - impl_def_id: ast::DefId) + impl_def_id: ast::DefId, + substs_fn: SubstsFn) -> (Rc>, Vec>) { let impl_substs = - &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id); + &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id); let impl_trait_ref = ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); let impl_trait_ref = @@ -134,12 +182,12 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, impl_def_id: ast::DefId) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("impl_is_local({})", impl_def_id.repr(tcx)); + debug!("orphan_check({})", impl_def_id.repr(tcx)); // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); - debug!("trait_ref={}", trait_ref.repr(tcx)); + debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx)); // If the *trait* is local to the crate, ok. if trait_ref.def_id.krate == ast::LOCAL_CRATE { @@ -148,34 +196,106 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, return Ok(()); } + orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false)) +} + +fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + param_is_local: ParamIsLocal) + -> Result<(), OrphanCheckErr<'tcx>> +{ + debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})", + trait_ref.repr(tcx), param_is_local.0); + // First, create an ordered iterator over all the type parameters to the trait, with the self // type appearing first. let input_tys = Some(trait_ref.self_ty()); let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter()); - let mut input_tys = input_tys; // Find the first input type that either references a type parameter OR // some local type. - match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) { - Some(&input_ty) => { - // Within this first type, check that all type parameters are covered by a local - // type constructor. Note that if there is no local type constructor, then any - // type parameter at all will be an error. - let covered_params = type_parameters_covered_by_ty(tcx, input_ty); - let all_params = type_parameters_reachable_from_ty(input_ty); - for ¶m in all_params.difference(&covered_params) { - return Err(OrphanCheckErr::UncoveredTy(param)); + for input_ty in input_tys { + if ty_is_local(tcx, input_ty, param_is_local) { + debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx)); + + // First local input type. Check that there are no + // uncovered type parameters. + let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local); + for uncovered_ty in uncovered_tys { + if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } + + // OK, found local type, all prior types upheld invariant. + return Ok(()); } - None => { - return Err(OrphanCheckErr::NoLocalInputType); + + // Otherwise, enforce invariant that there are no type + // parameters reachable. + if !param_is_local.0 { + if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } } - return Ok(()); + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + return Err(OrphanCheckErr::NoLocalInputType); +} + +fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> Vec> +{ + if ty_is_local_constructor(tcx, ty, param_is_local) { + vec![] + } else if fundamental_ty(tcx, ty) { + ty.walk_shallow() + .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter()) + .collect() + } else { + vec![ty] + } } -fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { +fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + // FIXME(#20590) straighten story about projection types + ty::ty_projection(..) | ty::ty_param(..) => true, + _ => false, + } +} + +fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool +{ + ty_is_local_constructor(tcx, ty, param_is_local) || + fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local)) +} + +fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool +{ + match ty.sty { + ty::ty_uniq(..) | ty::ty_rptr(..) => + true, + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => + ty::has_attr(tcx, def_id, "fundamental"), + ty::ty_trait(ref data) => + ty::has_attr(tcx, data.principal_def_id(), "fundamental"), + _ => + false + } +} + +fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> bool +{ debug!("ty_is_local_constructor({})", ty.repr(tcx)); match ty.sty { @@ -190,11 +310,15 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::ty_ptr(..) | ty::ty_rptr(..) | ty::ty_tup(..) | - ty::ty_param(..) | + ty::ty_infer(..) | ty::ty_projection(..) => { false } + ty::ty_param(..) => { + param_is_local.0 + } + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => { def_id.krate == ast::LOCAL_CRATE @@ -210,7 +334,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_closure(..) | - ty::ty_infer(..) | ty::ty_err => { tcx.sess.bug( &format!("ty_is_local invoked on unexpected type: {}", @@ -219,30 +342,4 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>) - -> HashSet> -{ - if ty_is_local_constructor(tcx, ty) { - type_parameters_reachable_from_ty(ty) - } else { - ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect() - } -} - -/// All type parameters reachable from `ty` -fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet> { - ty.walk().filter(|&t| is_type_parameter(t)).collect() -} - -fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty)) -} -fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { - match ty.sty { - // FIXME(#20590) straighten story about projection types - ty::ty_projection(..) | ty::ty_param(..) => true, - _ => false, - } -} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9e4f63dca4565..cb9d90744a446 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,6 +17,7 @@ use self::SelectionCandidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; +use super::coherence; use super::DerivedObligationCause; use super::project; use super::project::{normalize_with_depth, Normalized}; @@ -81,7 +82,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// selection-context's freshener. Used to check for recursion. fresh_trait_ref: ty::PolyTraitRef<'tcx>, - previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> + previous: TraitObligationStackList<'prev, 'tcx>, } #[derive(Clone)] @@ -245,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("select({})", obligation.repr(self.tcx())); assert!(!obligation.predicate.has_escaping_regions()); - let stack = self.push_stack(None, obligation); + let stack = self.push_stack(TraitObligationStackList::empty(), obligation); match try!(self.candidate_from_obligation(&stack)) { None => { self.consider_unification_despite_ambiguity(obligation); @@ -327,7 +328,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("evaluate_obligation({})", obligation.repr(self.tcx())); - self.evaluate_predicate_recursively(None, obligation).may_apply() + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + .may_apply() } fn evaluate_builtin_bound_recursively<'o>(&mut self, @@ -346,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match obligation { Ok(obligation) => { - self.evaluate_predicate_recursively(Some(previous_stack), &obligation) + self.evaluate_predicate_recursively(previous_stack.list(), &obligation) } Err(ErrorReported) => { EvaluatedToOk @@ -355,7 +357,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicates_recursively<'a,'o,I>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o, 'tcx>, predicates: I) -> EvaluationResult<'tcx> where I : Iterator>, 'tcx:'a @@ -372,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicate_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) -> EvaluationResult<'tcx> { @@ -423,14 +425,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_obligation_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &TraitObligation<'tcx>) -> EvaluationResult<'tcx> { debug!("evaluate_obligation_recursively({})", obligation.repr(self.tcx())); - let stack = self.push_stack(previous_stack.map(|x| x), obligation); + let stack = self.push_stack(previous_stack, obligation); let result = self.evaluate_stack(&stack); @@ -538,7 +540,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, skol_map, snapshot); - self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() + self.winnow_selection(TraitObligationStackList::empty(), + VtableImpl(vtable_impl)).may_apply() } Err(()) => { false @@ -607,6 +610,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(Some(ErrorCandidate)); } + if !self.is_knowable(stack) { + debug!("intercrate not knowable"); + return Ok(None); + } + let candidate_set = try!(self.assemble_candidates(stack)); if candidate_set.ambiguous { @@ -707,6 +715,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } + fn is_knowable<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> bool + { + debug!("is_knowable(intercrate={})", self.intercrate); + + if !self.intercrate { + return true; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); + + // ok to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions + let trait_ref = &predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> { // If there are any where-clauses in scope, then we always use // a cache local to this particular scope. Otherwise, we @@ -1026,7 +1055,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx().probe(move |_| { match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - self.evaluate_predicates_recursively(Some(stack), obligations.iter()) + self.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => { EvaluatedToErr(Unimplemented) @@ -1310,7 +1339,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); match self.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => self.winnow_selection(Some(stack), selection), + Ok(selection) => self.winnow_selection(stack.list(), + selection), Err(error) => EvaluatedToErr(error), } }); @@ -1320,7 +1350,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn winnow_selection<'o>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o,'tcx>, selection: Selection<'tcx>) -> EvaluationResult<'tcx> { @@ -2303,9 +2333,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation.cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation.cause.span, + impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); @@ -2423,9 +2453,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { // Create fresh type variables for each type parameter declared // on the impl etc. - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation_cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation_cause.span, + impl_def_id); // Find the self type for the impl. let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; @@ -2476,7 +2506,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Miscellany fn push_stack<'o,'s:'o>(&mut self, - previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>, + previous_stack: TraitObligationStackList<'s, 'tcx>, obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { @@ -2486,7 +2516,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitObligationStack { obligation: obligation, fresh_trait_ref: fresh_trait_ref, - previous: previous_stack.map(|p| p), // FIXME variance + previous: previous_stack, } } @@ -2639,17 +2669,36 @@ impl<'tcx> SelectionCache<'tcx> { } } -impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> { - Some(self) +impl<'o,'tcx> TraitObligationStack<'o,'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList::with(self) + } + + fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> { + self.list() } } -impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o,'tcx:'o> { + head: Option<&'o TraitObligationStack<'o,'tcx>> +} + +impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { + fn empty() -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: None } + } + + fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: Some(r) } + } +} + +impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ type Item = &'o TraitObligationStack<'o,'tcx>; - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match *self { + fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { + match self.head { Some(o) => { *self = o.previous; Some(o) @@ -2659,7 +2708,7 @@ impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { } } -impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> { +impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("TraitObligationStack({})", self.obligation.repr(tcx)) diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 7c7db4a64c02e..297cea13207e5 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::region; use middle::subst::{Substs, VecPerParamSpace}; use middle::infer::InferCtxt; use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef}; @@ -285,7 +286,6 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { } } - /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// @@ -294,16 +294,44 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { // declared on the impl declaration e.g., `impl for Box<[(A,B)]>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - impl_def_id: ast::DefId) - -> Substs<'tcx> +pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> { let tcx = infcx.tcx; let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; infcx.fresh_substs_for_generics(span, &impl_generics) } +// determine the `self` type, using fresh variables for all variables +// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` +// would return ($0, $1) where $0 and $1 are freshly instantiated type +// variables. +pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + _span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> +{ + let tcx = infcx.tcx; + let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + + let some_types = impl_generics.types.map(|def| { + ty::mk_param_from_def(tcx, def) + }); + + let some_regions = impl_generics.regions.map(|def| { + // FIXME. This destruction scope information is pretty darn + // bogus; after all, the impl might not even be in this crate! + // But given what we do in coherence, it is harmless enough + // for now I think. -nmatsakis + let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID); + ty::free_region_from_def(extent, def) + }); + + Substs::new(some_types, some_regions) +} + impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VtableImpl({:?})", self.impl_def_id) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6e81d14d73cad..0814ec2c84e70 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -58,7 +58,7 @@ use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; -use middle::ty_walk::TypeWalker; +use middle::ty_walk::{self, TypeWalker}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::ty_to_string; use util::ppaux::{Repr, UserString}; @@ -89,7 +89,8 @@ use syntax::codemap::Span; use syntax::parse::token::{self, InternedString, special_idents}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::{ast, ast_map}; +use syntax::ast; +use syntax::ast_map::{self, LinkedPath}; pub type Disr = u64; @@ -3167,21 +3168,11 @@ impl<'tcx> TyS<'tcx> { TypeWalker::new(self) } - /// Iterator that walks types reachable from `self`, in - /// depth-first order. Note that this is a shallow walk. For - /// example: - /// - /// ```notrust - /// isize => { } - /// Foo> => { Bar, isize } - /// [isize] => { isize } - /// ``` - pub fn walk_children(&'tcx self) -> TypeWalker<'tcx> { - // Walks type reachable from `self` but not `self - let mut walker = self.walk(); - let r = walker.next(); - assert_eq!(r, Some(self)); - walker + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(&'tcx self) -> IntoIter> { + ty_walk::walk_shallow(self) } pub fn as_opt_param_ty(&self) -> Option { @@ -5484,7 +5475,7 @@ pub fn with_path(cx: &ctxt, id: ast::DefId, f: F) -> T where if id.krate == ast::LOCAL_CRATE { cx.map.with_path(id.node, f) } else { - f(csearch::get_item_path(cx, id).iter().cloned().chain(None)) + f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty())) } } diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 5d492f1c95e11..ec09d6dcc1ee2 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -12,6 +12,7 @@ use middle::ty::{self, Ty}; use std::iter::Iterator; +use std::vec::IntoIter; pub struct TypeWalker<'tcx> { stack: Vec>, @@ -23,60 +24,6 @@ impl<'tcx> TypeWalker<'tcx> { TypeWalker { stack: vec!(ty), last_subtree: 1, } } - fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) { - match parent_ty.sty { - ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | - ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { - } - ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { - self.stack.push(ty); - } - ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - self.stack.push(mt.ty); - } - ty::ty_projection(ref data) => { - self.push_reversed(data.trait_ref.substs.types.as_slice()); - } - ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - self.push_reversed(principal.substs().types.as_slice()); - self.push_reversed(&bounds.projection_bounds.iter().map(|pred| { - pred.0.ty - }).collect::>()); - } - ty::ty_enum(_, ref substs) | - ty::ty_struct(_, ref substs) | - ty::ty_closure(_, ref substs) => { - self.push_reversed(substs.types.as_slice()); - } - ty::ty_tup(ref ts) => { - self.push_reversed(ts); - } - ty::ty_bare_fn(_, ref ft) => { - self.push_sig_subtypes(&ft.sig); - } - } - } - - fn push_sig_subtypes(&mut self, sig: &ty::PolyFnSig<'tcx>) { - match sig.0.output { - ty::FnConverging(output) => { self.stack.push(output); } - ty::FnDiverging => { } - } - self.push_reversed(&sig.0.inputs); - } - - fn push_reversed(&mut self, tys: &[Ty<'tcx>]) { - // We push slices on the stack in reverse order so as to - // maintain a pre-order traversal. As of the time of this - // writing, the fact that the traversal is pre-order is not - // known to be significant to any code, but it seems like the - // natural order one would expect (basically, the order of the - // types as they are written). - for &ty in tys.iter().rev() { - self.stack.push(ty); - } - } - /// Skips the subtree of types corresponding to the last type /// returned by `next()`. /// @@ -105,10 +52,70 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } Some(ty) => { self.last_subtree = self.stack.len(); - self.push_subtypes(ty); + push_subtypes(&mut self.stack, ty); debug!("next: stack={:?}", self.stack); Some(ty) } } } } + +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { + let mut stack = vec![]; + push_subtypes(&mut stack, ty); + stack.into_iter() +} + +fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { + match parent_ty.sty { + ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | + ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { + } + ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { + stack.push(ty); + } + ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { + stack.push(mt.ty); + } + ty::ty_projection(ref data) => { + push_reversed(stack, data.trait_ref.substs.types.as_slice()); + } + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { + push_reversed(stack, principal.substs().types.as_slice()); + push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { + pred.0.ty + }).collect::>()); + } + ty::ty_enum(_, ref substs) | + ty::ty_struct(_, ref substs) | + ty::ty_closure(_, ref substs) => { + push_reversed(stack, substs.types.as_slice()); + } + ty::ty_tup(ref ts) => { + push_reversed(stack, ts); + } + ty::ty_bare_fn(_, ref ft) => { + push_sig_subtypes(stack, &ft.sig); + } + } +} + +fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { + match sig.0.output { + ty::FnConverging(output) => { stack.push(output); } + ty::FnDiverging => { } + } + push_reversed(stack, &sig.0.inputs); +} + +fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { + // We push slices on the stack in reverse order so as to + // maintain a pre-order traversal. As of the time of this + // writing, the fact that the traversal is pre-order is not + // known to be significant to any code, but it seems like the + // natural order one would expect (basically, the order of the + // types as they are written). + for &ty in tys.iter().rev() { + stack.push(ty); + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 452589a240754..4405a9d75ee62 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -384,13 +384,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { } ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty), ty_err => "[type error]".to_string(), - ty_param(ref param_ty) => { - if cx.sess.verbose() { - param_ty.repr(cx) - } else { - param_ty.user_string(cx) - } - } + ty_param(ref param_ty) => param_ty.user_string(cx), ty_enum(did, substs) | ty_struct(did, substs) => { let base = ty::item_path_str(cx, did); parameterized(cx, &base, substs, did, &[], diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f88381fb36f86..113827a3b402f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -91,6 +91,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("start", "1.0.0", Active), ("main", "1.0.0", Active), + ("fundamental", "1.0.0", Active), + // Deprecate after snapshot // SNAP 5520801 ("unsafe_destructor", "1.0.0", Active), @@ -237,6 +239,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("allow_internal_unstable", Gated("allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), + ("fundamental", Gated("fundamental", + "the `#[fundamental]` attribute \ + is an experimental feature")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), From 35c261aea0d891d31b3fda83da653cb1e385681f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:52:00 -0400 Subject: [PATCH 25/28] Add `#[fundamental]` annotations into libcore so that `Sized` and the `Fn` traits are considered fundamental, along with `Box` (though that is mostly for show; the real type is `~T` in the compiler). --- src/liballoc/boxed.rs | 1 + src/liballoc/lib.rs | 2 ++ src/libcore/lib.rs | 2 ++ src/libcore/marker.rs | 1 + src/libcore/ops.rs | 3 +++ 5 files changed, 9 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 550b25ac3a7cf..adfe0f461bea3 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -86,6 +86,7 @@ pub static HEAP: () = (); /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] +#[fundamental] pub struct Box(Unique); impl Box { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b92dfa9117e6b..a8be63d637359 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -71,6 +71,8 @@ #![feature(no_std)] #![no_std] #![feature(allocator)] +#![feature(custom_attribute)] +#![feature(fundamental)] #![feature(lang_items, unsafe_destructor)] #![feature(box_syntax)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5e8b7fba1f15c..3a9af50fefbc7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,8 +70,10 @@ #![feature(unboxed_closures)] #![feature(rustc_attrs)] #![feature(optin_builtin_traits)] +#![feature(fundamental)] #![feature(concat_idents)] #![feature(reflect)] +#![feature(custom_attribute)] #[macro_use] mod macros; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f755c912fcd4a..97bde9fc96eec 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -49,6 +49,7 @@ impl !Send for Managed { } #[stable(feature = "rust1", since = "1.0.0")] #[lang="sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized : MarkerTrait { // Empty. } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 862eb16d0bfb3..399aec9afd440 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1117,6 +1117,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { #[lang="fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait Fn : FnMut { /// This is called when the call operator is used. extern "rust-call" fn call(&self, args: Args) -> Self::Output; @@ -1126,6 +1127,7 @@ pub trait Fn : FnMut { #[lang="fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnMut : FnOnce { /// This is called when the call operator is used. extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; @@ -1135,6 +1137,7 @@ pub trait FnMut : FnOnce { #[lang="fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnOnce { /// The returned type after the call operator is used. type Output; From b0af587b64786b45ac9651ee4608e1edbd53a733 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:49:30 -0400 Subject: [PATCH 26/28] Update tests for new coherence rules, and add a swatch of new tests probing the specifics of `Fundamental`. Fixes #23086. Fixes #23516. --- src/test/auxiliary/coherence_copy_like_lib.rs | 22 ++++++++++++ .../coherence-cow-1.rs | 9 +++-- .../coherence-cow-2.rs | 8 +++-- .../compile-fail/coherence-cow-no-cover.rs | 4 +-- src/test/compile-fail/coherence-impls-copy.rs | 7 ++++ src/test/compile-fail/coherence-impls-send.rs | 8 ++--- .../compile-fail/coherence-impls-sized.rs | 11 ++++-- .../coherence-overlap-issue-23516.rs | 19 ++++++++++ .../coherence-vec-local-2.rs} | 5 ++- .../coherence-vec-local.rs} | 5 ++- ...erence_copy_like_err_fundamental_struct.rs | 36 +++++++++++++++++++ ...ce_copy_like_err_fundamental_struct_ref.rs | 36 +++++++++++++++++++ ..._copy_like_err_fundamental_struct_tuple.rs | 32 +++++++++++++++++ .../coherence_copy_like_err_struct.rs | 33 +++++++++++++++++ .../coherence_copy_like_err_tuple.rs | 32 +++++++++++++++++ src/test/compile-fail/coherence_local.rs | 33 +++++++++++++++++ .../coherence_local_err_struct.rs | 29 +++++++++++++++ .../compile-fail/coherence_local_err_tuple.rs | 29 +++++++++++++++ src/test/compile-fail/coherence_local_ref.rs | 27 ++++++++++++++ ...efault-trait-impl-cross-crate-coherence.rs | 6 ++-- src/test/run-pass/coherence_copy_like.rs | 29 +++++++++++++++ .../method-two-trait-defer-resolution-2.rs | 31 +++++++++------- .../run-pass/traits-conditional-dispatch.rs | 16 ++++++--- 23 files changed, 431 insertions(+), 36 deletions(-) create mode 100644 src/test/auxiliary/coherence_copy_like_lib.rs rename src/test/{run-pass => compile-fail}/coherence-cow-1.rs (71%) rename src/test/{run-pass => compile-fail}/coherence-cow-2.rs (67%) create mode 100644 src/test/compile-fail/coherence-overlap-issue-23516.rs rename src/test/{run-pass/coherence-local-2.rs => compile-fail/coherence-vec-local-2.rs} (77%) rename src/test/{run-pass/coherence-local-1.rs => compile-fail/coherence-vec-local.rs} (76%) create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_struct.rs create mode 100644 src/test/compile-fail/coherence_copy_like_err_tuple.rs create mode 100644 src/test/compile-fail/coherence_local.rs create mode 100644 src/test/compile-fail/coherence_local_err_struct.rs create mode 100644 src/test/compile-fail/coherence_local_err_tuple.rs create mode 100644 src/test/compile-fail/coherence_local_ref.rs create mode 100644 src/test/run-pass/coherence_copy_like.rs diff --git a/src/test/auxiliary/coherence_copy_like_lib.rs b/src/test/auxiliary/coherence_copy_like_lib.rs new file mode 100644 index 0000000000000..a1e1b48c2c4e9 --- /dev/null +++ b/src/test/auxiliary/coherence_copy_like_lib.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(fundamental)] + +use std::marker::MarkerTrait; + +pub trait MyCopy : MarkerTrait { } +impl MyCopy for i32 { } + +pub struct MyStruct(T); + +#[fundamental] +pub struct MyFundamentalStruct(T); diff --git a/src/test/run-pass/coherence-cow-1.rs b/src/test/compile-fail/coherence-cow-1.rs similarity index 71% rename from src/test/run-pass/coherence-cow-1.rs rename to src/test/compile-fail/coherence-cow-1.rs index 31f6c9af02024..530bbf57d9104 100644 --- a/src/test/run-pass/coherence-cow-1.rs +++ b/src/test/compile-fail/coherence-cow-1.rs @@ -10,16 +10,19 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear first in the self-type, as long -// as it's covered somewhere. - // pretty-expanded FIXME #23616 +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. + extern crate coherence_lib as lib; use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair> { } +//~^ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-cow-2.rs b/src/test/compile-fail/coherence-cow-2.rs similarity index 67% rename from src/test/run-pass/coherence-cow-2.rs rename to src/test/compile-fail/coherence-cow-2.rs index ccda8440ea228..52abceab98b69 100644 --- a/src/test/run-pass/coherence-cow-2.rs +++ b/src/test/compile-fail/coherence-cow-2.rs @@ -10,8 +10,10 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear second in the self-type, as long -// as it's covered somewhere. +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. // pretty-expanded FIXME #23616 @@ -20,6 +22,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); -impl Remote for Pair,T> { } +impl Remote for Pair,T> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/compile-fail/coherence-cow-no-cover.rs b/src/test/compile-fail/coherence-cow-no-cover.rs index 475d7df1fdb4f..cd32e797ae9bf 100644 --- a/src/test/compile-fail/coherence-cow-no-cover.rs +++ b/src/test/compile-fail/coherence-cow-no-cover.rs @@ -10,7 +10,7 @@ // aux-build:coherence_lib.rs -// Test that it's not ok for U to appear uncovered +// Test that it's not ok for T to appear uncovered extern crate coherence_lib as lib; use lib::{Remote,Pair}; @@ -18,6 +18,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair,U> { } -//~^ ERROR type parameter `U` must be used as the type parameter for some local type +//~^ ERROR type parameter `T` must be used as the type parameter for some local type fn main() { } diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index 3034be177ca68..b99b2e1205b9b 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -23,17 +23,24 @@ impl !Sync for NotSync {} impl Copy for TestE {} impl Copy for MyType {} + +impl Copy for &'static mut MyType {} +//~^ ERROR E0206 + impl Copy for (MyType, MyType) {} //~^ ERROR E0206 +//~| ERROR E0117 impl Copy for &'static NotSync {} //~^ ERROR E0206 impl Copy for [MyType] {} //~^ ERROR E0206 +//~| ERROR E0117 impl Copy for &'static [NotSync] {} //~^ ERROR E0206 +//~| ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index b05c1ff0f0b72..f130a9353516f 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -24,17 +24,17 @@ impl !Sync for NotSync {} unsafe impl Send for TestE {} unsafe impl Send for MyType {} unsafe impl Send for (MyType, MyType) {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static NotSync {} //~^ ERROR E0321 unsafe impl Send for [MyType] {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static [NotSync] {} -//~^ ERROR E0321 -//~| ERROR conflicting implementations +//~^ ERROR E0117 +//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index a9a3ebaffb75a..2ac4bb0492b1f 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -22,12 +22,17 @@ struct NotSync; impl !Sync for NotSync {} impl Sized for TestE {} //~ ERROR E0322 + impl Sized for MyType {} //~ ERROR E0322 -impl Sized for (MyType, MyType) {} //~ ERROR E0322 + +impl Sized for (MyType, MyType) {} //~ ERROR E0117 + impl Sized for &'static NotSync {} //~ ERROR E0322 -impl Sized for [MyType] {} //~ ERROR E0322 + +impl Sized for [MyType] {} //~ ERROR E0117 //~^ ERROR E0277 -impl Sized for &'static [NotSync] {} //~ ERROR E0322 + +impl Sized for &'static [NotSync] {} //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-overlap-issue-23516.rs b/src/test/compile-fail/coherence-overlap-issue-23516.rs new file mode 100644 index 0000000000000..d7f060a3bfe73 --- /dev/null +++ b/src/test/compile-fail/coherence-overlap-issue-23516.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that we consider `Box: !Sugar` to be ambiguous, even +// though we see no impl of `Sugar` for `Box`. Therefore, an overlap +// error is reported for the following pair of impls (#23516). + +pub trait Sugar { fn dummy(&self) { } } +pub trait Sweet { fn dummy(&self) { } } +impl Sweet for T { } //~ ERROR E0119 +impl Sweet for Box { } +fn main() { } diff --git a/src/test/run-pass/coherence-local-2.rs b/src/test/compile-fail/coherence-vec-local-2.rs similarity index 77% rename from src/test/run-pass/coherence-local-2.rs rename to src/test/compile-fail/coherence-vec-local-2.rs index 5fd3e8ca86ef7..5f0b56af2c226 100644 --- a/src/test/run-pass/coherence-local-2.rs +++ b/src/test/compile-fail/coherence-vec-local-2.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local, generic type appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local(T); -impl Remote for Vec> { } +impl Remote for Vec> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-local-1.rs b/src/test/compile-fail/coherence-vec-local.rs similarity index 76% rename from src/test/run-pass/coherence-local-1.rs rename to src/test/compile-fail/coherence-vec-local.rs index 21faa30245d9a..c354caac2b5c2 100644 --- a/src/test/run-pass/coherence-local-1.rs +++ b/src/test/compile-fail/coherence-vec-local.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local type (with no type parameters) appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local; -impl Remote for Vec { } +impl Remote for Vec { } //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs new file mode 100644 index 0000000000000..f13175ce8e2a4 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct: !MyTrait +// +// Huzzah. +impl MyTrait for lib::MyFundamentalStruct { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs new file mode 100644 index 0000000000000..ae3d242af705e --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct<&MyTrait>: !MyTrait +// +// Huzzah. +impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs new file mode 100644 index 0000000000000..c4e95e772356a --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } + +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental. +impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs new file mode 100644 index 0000000000000..f768a475ee820 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:coherence_copy_like_lib.rs + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// `MyStruct` is not declared fundamental, therefore this would +// require that +// +// MyStruct: !MyTrait +// +// which we cannot approve. +impl MyTrait for lib::MyStruct { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs new file mode 100644 index 0000000000000..0c78fffd2dfab --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental, therefore this would require that +// +// (MyType,): !MyTrait +// +// which we cannot approve. +impl MyTrait for (MyType,) { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_local.rs b/src/test/compile-fail/coherence_local.rs new file mode 100644 index 0000000000000..551577b6b4e08 --- /dev/null +++ b/src/test/compile-fail/coherence_local.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +impl lib::MyCopy for MyType { } +impl<'a> lib::MyCopy for &'a MyType { } +impl<'a> lib::MyCopy for &'a Box { } +impl lib::MyCopy for Box { } +impl lib::MyCopy for lib::MyFundamentalStruct { } +impl lib::MyCopy for lib::MyFundamentalStruct> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_local_err_struct.rs b/src/test/compile-fail/coherence_local_err_struct.rs new file mode 100644 index 0000000000000..01f4c1cd8a5c9 --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_struct.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// MyStruct is not fundamental. +impl lib::MyCopy for lib::MyStruct { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_err_tuple.rs b/src/test/compile-fail/coherence_local_err_tuple.rs new file mode 100644 index 0000000000000..590f68cee59ef --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_tuple.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// Tuples are not fundamental, so this is not a local impl. +impl lib::MyCopy for (MyType,) { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_ref.rs b/src/test/compile-fail/coherence_local_ref.rs new file mode 100644 index 0000000000000..f6e1aab59766a --- /dev/null +++ b/src/test/compile-fail/coherence_local_ref.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// naturally, legal +impl lib::MyCopy for MyType { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs index 7d25c04882f24..b1febae768036 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs @@ -20,15 +20,15 @@ extern crate typeck_default_trait_impl_cross_crate_coherence_lib as lib; use lib::DefaultedTrait; struct A; -impl DefaultedTrait for (A,) { } //~ ERROR E0321 +impl DefaultedTrait for (A,) { } //~ ERROR E0117 struct B; -impl !DefaultedTrait for (B,) { } //~ ERROR E0321 +impl !DefaultedTrait for (B,) { } //~ ERROR E0117 struct C; struct D(T); impl DefaultedTrait for Box { } //~ ERROR E0321 -impl DefaultedTrait for lib::Something { } //~ ERROR E0321 +impl DefaultedTrait for lib::Something { } //~ ERROR E0117 impl DefaultedTrait for D { } // OK fn main() { } diff --git a/src/test/run-pass/coherence_copy_like.rs b/src/test/run-pass/coherence_copy_like.rs new file mode 100644 index 0000000000000..db9893613ad11 --- /dev/null +++ b/src/test/run-pass/coherence_copy_like.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } +impl MyTrait for MyType { } +impl<'a> MyTrait for &'a MyType { } +impl MyTrait for Box { } +impl<'a> MyTrait for &'a Box { } + +fn main() { } diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index d87ed03e94e01..2ceff22adb9eb 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -8,13 +8,16 @@ // 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()`). +// Test that when we write `x.foo()`, we do nothave to know the +// complete type of `x` in order to type-check the method call. In +// this case, we know that `x: Vec<_1>`, but we don't know what type +// `_1` is (because the call to `push` comes later). To pick between +// the impls, we would have to know `_1`, since we have to know +// whether `_1: MyCopy` or `_1 == Box`. However (and this is the +// point of the test), we don't have to pick between the two impls -- +// it is enough to know that `foo` comes from the `Foo` trait. We can +// translate the call as `Foo::foo(&x)` and let the specific impl get +// chosen later. // pretty-expanded FIXME #23616 @@ -25,25 +28,29 @@ trait Foo { fn foo(&self) -> isize; } -impl Foo for Vec { +trait MyCopy { fn foo(&self) { } } +impl MyCopy for i32 { } + +impl Foo for Vec { fn foo(&self) -> isize {1} } -impl Foo for Vec> { +impl Foo for Vec> { fn foo(&self) -> isize {2} } fn call_foo_copy() -> isize { let mut x = Vec::new(); let y = x.foo(); - x.push(0_usize); + x.push(0_i32); y } fn call_foo_other() -> isize { - let mut x: Vec> = Vec::new(); + let mut x: Vec<_> = Vec::new(); let y = x.foo(); - x.push(box 0); + let z: Box = box 0; + x.push(z); y } diff --git a/src/test/run-pass/traits-conditional-dispatch.rs b/src/test/run-pass/traits-conditional-dispatch.rs index 5edd3dfbc9ef5..0190b7b7b9628 100644 --- a/src/test/run-pass/traits-conditional-dispatch.rs +++ b/src/test/run-pass/traits-conditional-dispatch.rs @@ -17,16 +17,24 @@ #![allow(unknown_features)] #![feature(box_syntax)] +use std::marker::MarkerTrait; + trait Get { fn get(&self) -> Self; } -impl Get for T { - fn get(&self) -> T { *self } +trait MyCopy : MarkerTrait { fn copy(&self) -> Self; } +impl MyCopy for u16 { fn copy(&self) -> Self { *self } } +impl MyCopy for u32 { fn copy(&self) -> Self { *self } } +impl MyCopy for i32 { fn copy(&self) -> Self { *self } } +impl MyCopy for Option { fn copy(&self) -> Self { *self } } + +impl Get for T { + fn get(&self) -> T { self.copy() } } -impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } } fn get_it(t: &T) -> T { From 30b2d9e7643de3a267029c2763edb0b44ff2396e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:50:31 -0400 Subject: [PATCH 27/28] Fallout in libstd: remove impls now considered to conflict. --- src/liballoc/boxed.rs | 7 ------- src/liballoc/boxed_test.rs | 8 ++++---- src/libcore/any.rs | 8 ++++++++ src/libcore/fmt/mod.rs | 6 ------ 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index adfe0f461bea3..c4541e34cdb35 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -278,13 +278,6 @@ impl fmt::Debug for Box { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Box") - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Box { type Target = T; diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 682d5f407c4ea..fc44ac4eac628 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -55,17 +55,17 @@ fn test_show() { let b = Box::new(Test) as Box; let a_str = format!("{:?}", a); let b_str = format!("{:?}", b); - assert_eq!(a_str, "Box"); - assert_eq!(b_str, "Box"); + assert_eq!(a_str, "Any"); + assert_eq!(b_str, "Any"); static EIGHT: usize = 8; static TEST: Test = Test; let a = &EIGHT as &Any; let b = &TEST as &Any; let s = format!("{:?}", a); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); let s = format!("{:?}", b); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); } #[test] diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 0ffc4a229b5ae..320fdd50b3510 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -71,6 +71,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use fmt; use marker::Send; use mem::transmute; use option::Option::{self, Some, None}; @@ -105,6 +106,13 @@ impl Any for T // Extension methods for Any trait objects. /////////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Any { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + impl Any { /// Returns true if the boxed type is the same as `T` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index ffb358cdac84d..3f8bbeb1feb88 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,7 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use any; use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use char::CharExt; use iter::Iterator; @@ -997,11 +996,6 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Debug for &'a (any::Any+'a) { - fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { fn fmt(&self, f: &mut Formatter) -> Result { From 15b58fedcacba7d10a9f7d460a83da645a09ad3e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 30 Mar 2015 17:51:26 -0400 Subject: [PATCH 28/28] Fallout in libsyntax/librustc: use newtype'd options for linked lists, since `Option` is not fundamental and hence the old impls run afoul of the orphan rules. --- src/librustc/metadata/encoder.rs | 7 +++---- src/libsyntax/ast_map/mod.rs | 21 ++++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a8f83bee7f682..862ced78c082c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -34,8 +34,7 @@ use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; use syntax::abi; use syntax::ast::{self, DefId, NodeId}; -use syntax::ast_map::{PathElem, PathElems}; -use syntax::ast_map; +use syntax::ast_map::{self, LinkedPath, PathElem, PathElems}; use syntax::ast_util::*; use syntax::ast_util; use syntax::attr; @@ -1513,7 +1512,7 @@ fn encode_info_for_items(ecx: &EncodeContext, &krate.module, &[], ast::CRATE_NODE_ID, - [].iter().cloned().chain(None), + [].iter().cloned().chain(LinkedPath::empty()), syntax::parse::token::special_idents::invalid, ast::Public); @@ -1874,7 +1873,7 @@ fn encode_misc_info(ecx: &EncodeContext, } // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(None)); + encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty())); rbml_w.end_tag(); rbml_w.end_tag(); diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 48bb044cb1854..2b5cb7076f463 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -53,18 +53,29 @@ impl fmt::Display for PathElem { } #[derive(Clone)] -struct LinkedPathNode<'a> { +pub struct LinkedPathNode<'a> { node: PathElem, next: LinkedPath<'a>, } -type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>; +#[derive(Copy, Clone)] +pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); + +impl<'a> LinkedPath<'a> { + pub fn empty() -> LinkedPath<'a> { + LinkedPath(None) + } + + pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { + LinkedPath(Some(node)) + } +} impl<'a> Iterator for LinkedPath<'a> { type Item = PathElem; fn next(&mut self) -> Option { - match *self { + match self.0 { Some(node) => { *self = node.next; Some(node.node) @@ -384,7 +395,7 @@ impl<'ast> Map<'ast> { pub fn with_path(&self, id: NodeId, f: F) -> T where F: FnOnce(PathElems) -> T, { - self.with_path_next(id, None, f) + self.with_path_next(id, LinkedPath::empty(), f) } pub fn path_to_string(&self, id: NodeId) -> String { @@ -422,7 +433,7 @@ impl<'ast> Map<'ast> { _ => f([].iter().cloned().chain(next)) } } else { - self.with_path_next(parent, Some(&LinkedPathNode { + self.with_path_next(parent, LinkedPath::from(&LinkedPathNode { node: self.get_path_elem(id), next: next }), f)