From 514dfdbf12b71758c7abc3219ae1a3936e4d59d9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 29 Nov 2014 08:06:42 -0500 Subject: [PATCH 01/24] Add tests for sub relationship on free/bound regions, revealing a bug. --- src/librustc_driver/test.rs | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 508af4c28e66c..943650ce8a63b 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -25,6 +25,7 @@ use rustc_typeck::middle::infer::combine::Combine; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; +use rustc_typeck::middle::infer::sub::Sub; use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString}; use rustc::session::{mod,config}; use syntax::{abi, ast, ast_map, ast_util}; @@ -341,6 +342,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { infer::TypeTrace::dummy() } + pub fn sub(&self) -> Sub<'a, 'tcx> { + let trace = self.dummy_type_trace(); + Sub(self.infcx.combine_fields(true, trace)) + } + pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); Lub(self.infcx.combine_fields(true, trace)) @@ -359,6 +365,33 @@ 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) { + Ok(_) => { } + Err(ref e) => { + panic!("unexpected error computing sub({},{}): {}", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx), + ty::type_err_to_str(self.infcx.tcx, e)); + } + } + } + + /// 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) { + Err(_) => { } + Ok(_) => { + panic!("unexpected success computing sub({},{})", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.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) { @@ -421,6 +454,54 @@ fn contravariant_region_ptr_err() { }) } +#[test] +fn sub_free_bound_false() { + //! Test that: + //! + //! fn(&'a int) <: for<'b> fn(&'b int) + //! + //! does NOT hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_rptr_free1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn sub_bound_free_true() { + //! Test that: + //! + //! for<'a> fn(&'a int) <: fn(&'b int) + //! + //! DOES hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_sub(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }) +} + +#[test] +fn sub_free_bound_false_infer() { + //! Test that: + //! + //! fn(_#1) <: for<'b> fn(&'b int) + //! + //! does NOT hold for any instantiation of `_#1`. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + #[test] fn lub_bound_bound() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { From 3efc9d2c55af6e58dd96c5814260bacc2b582ef3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Dec 2014 10:11:59 -0500 Subject: [PATCH 02/24] Fix bug in higher-ranked code that would sometimes leak skolemized regions and/or cause incorrect results. --- src/librustc/middle/infer/coercion.rs | 10 +- src/librustc/middle/infer/combine.rs | 36 +- src/librustc/middle/infer/error_reporting.rs | 4 +- .../middle/infer/higher_ranked/doc.rs | 28 +- .../middle/infer/higher_ranked/mod.rs | 363 +++++++++++------- src/librustc/middle/infer/mod.rs | 49 +-- .../middle/infer/region_inference/mod.rs | 27 +- src/librustc/middle/infer/resolve.rs | 35 ++ src/librustc/middle/infer/type_variable.rs | 46 ++- src/librustc/middle/ty_fold.rs | 11 + src/librustc/util/snapshot_vec.rs | 8 +- src/librustc_driver/test.rs | 42 ++ src/librustc_typeck/check/closure.rs | 4 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 10 +- src/librustc_typeck/check/vtable.rs | 19 +- src/test/compile-fail/bad-match.rs | 3 + 17 files changed, 456 insertions(+), 241 deletions(-) diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index e268160a42b85..43d99ecb427a7 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -286,7 +286,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -309,7 +309,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -327,7 +327,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match self.unsize_ty(t_a, sty_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -384,7 +384,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } match @@ -397,7 +397,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, new_substs); - if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { + if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 26bba55594b5e..1b72a572e9ec0 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -706,14 +706,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { - ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, - _ if self.make_region_vars => { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx.next_region_var(MiscVariable(self.span)) + // Never make variables for regions bound within the type itself. + ty::ReLateBound(..) => { return r; } + + // Early-bound regions should really have been substituted away before + // we get to this point. + ty::ReEarlyBound(..) => { + self.tcx().sess.span_bug( + self.span, + format!("Encountered early bound region when generalizing: {}", + r.repr(self.tcx()))[]); + } + + // Always make a fresh region variable for skolemized regions; + // the higher-ranked decision procedures rely on this. + ty::ReInfer(ty::ReSkolemized(..)) => { } + + // For anything else, we make a region variable, unless we + // are *equating*, in which case it's just wasteful. + ty::ReEmpty | + ty::ReStatic | + ty::ReScope(..) | + ty::ReInfer(ty::ReVar(..)) | + ty::ReFree(..) => { + if !self.make_region_vars { + return r; + } } - _ => r, } + + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx.next_region_var(MiscVariable(self.span)) } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index ab685dd5dbc13..e1473847c235b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1640,7 +1640,7 @@ pub trait Resolvable<'tcx> { impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(*self) + infcx.resolve_type_vars_if_possible(self) } fn contains_error(&self) -> bool { ty::type_is_error(*self) @@ -1650,7 +1650,7 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { impl<'tcx> Resolvable<'tcx> for Rc> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc> { - Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self)) + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { ty::trait_ref_contains_error(&**self) diff --git a/src/librustc/middle/infer/higher_ranked/doc.rs b/src/librustc/middle/infer/higher_ranked/doc.rs index 2bad3616a05d1..f6f254c0e8dfc 100644 --- a/src/librustc/middle/infer/higher_ranked/doc.rs +++ b/src/librustc/middle/infer/higher_ranked/doc.rs @@ -249,19 +249,21 @@ //! in T and try to, in some cases, replace them with bound regions to //! yield the final result. //! -//! To decide whether to replace a region `R` that appears in `T` with a -//! bound region, the algorithms make use of two bits of information. -//! First is a set `V` that contains all region variables created as part -//! of the LUB/GLB computation. `V` will contain the region variables -//! created to replace the bound regions in the input types, but it also -//! contains 'intermediate' variables created to represent the LUB/GLB of -//! individual regions. Basically, when asked to compute the LUB/GLB of a -//! region variable with another region, the inferencer cannot oblige -//! immediately since the values of that variables are not known. -//! Therefore, it creates a new variable that is related to the two -//! regions. For example, the LUB of two variables `$x` and `$y` is a -//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y -//! <= $z`. So `V` will contain these intermediate variables as well. +//! To decide whether to replace a region `R` that appears in `T` with +//! a bound region, the algorithms make use of two bits of +//! information. First is a set `V` that contains all region +//! variables created as part of the LUB/GLB computation (roughly; see +//! `region_vars_confined_to_snapshot()` for full details). `V` will +//! contain the region variables created to replace the bound regions +//! in the input types, but it also contains 'intermediate' variables +//! created to represent the LUB/GLB of individual regions. +//! Basically, when asked to compute the LUB/GLB of a region variable +//! with another region, the inferencer cannot oblige immediately +//! since the values of that variables are not known. Therefore, it +//! creates a new variable that is related to the two regions. For +//! example, the LUB of two variables `$x` and `$y` is a fresh +//! variable `$z` that is constrained such that `$x <= $z` and `$y <= +//! $z`. So `V` will contain these intermediate variables as well. //! //! The other important factor in deciding how to replace a region in T is //! the function `Tainted($r)` which, for a region variable, identifies diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index be053afcca436..0a2049bef48f2 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,14 +11,13 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{combine, cres, InferCtxt, HigherRankedType}; +use super::{combine, CombinedSnapshot, cres, InferCtxt, HigherRankedType}; use super::combine::Combine; -use super::region_inference::{RegionMark}; use middle::ty::{mod, Ty, replace_late_bound_regions}; use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; use syntax::codemap::Span; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::{bound_region_to_string, Repr}; pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> + @@ -37,6 +36,14 @@ pub trait HigherRankedRelations<'tcx> { where T : HigherRankedCombineable<'tcx>; } +trait InferCtxtExt<'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec; + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec; +} + impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { @@ -54,114 +61,115 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // please see the large comment at the end of the file in the (inlined) module // `doc`. - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // 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(), - HigherRankedType, - a); - - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = { - replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = self.infcx().region_vars.new_skolemized(br); - debug!("Bound region {} skolemized to {}", - bound_region_to_string(self.tcx(), "", false, br), - skol); - skol - }) - }; - - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); - - // Compare types now that bound regions have been replaced. - let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - let new_vars = - self.infcx().region_vars.vars_created_since_mark(mark); - for (&skol_br, &skol) in skol_map.iter() { - let tainted = self.infcx().region_vars.tainted(mark, skol); - for tainted_region in tainted.iter() { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReInfer(ty::ReVar(ref vid)) => { - if new_vars.iter().any(|x| x == vid) { continue; } - } - _ => { - if *tainted_region == skol { continue; } + return self.infcx().try(|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(), + HigherRankedType, + a); + + // Second, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, skol_map) = { + replace_late_bound_regions(self.tcx(), b, |br, _| { + let skol = self.infcx().region_vars.new_skolemized(br); + debug!("Bound region {} skolemized to {}", + bound_region_to_string(self.tcx(), "", false, br), + skol); + skol + }) + }; + + debug!("a_prime={}", a_prime.repr(self.tcx())); + debug!("b_prime={}", b_prime.repr(self.tcx())); + + // Compare types now that bound regions have been replaced. + let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); + + // Presuming type comparison succeeds, we need to check + // that the skolemized regions do not "leak". + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map.iter() { + let tainted = self.infcx().tainted_regions(snapshot, skol); + for tainted_region in tainted.iter() { + // Each skolemized should only be relatable to itself + // or new variables: + match *tainted_region { + ty::ReInfer(ty::ReVar(ref vid)) => { + if new_vars.iter().any(|x| x == vid) { continue; } + } + _ => { + if *tainted_region == skol { continue; } + } + }; + + // A is not as polymorphic as B: + if self.a_is_expected() { + debug!("Not as polymorphic!"); + return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, + *tainted_region)); + } else { + debug!("Overly polymorphic!"); + return Err(ty::terr_regions_overly_polymorphic(skol_br, + *tainted_region)); } - }; - - // A is not as polymorphic as B: - if self.a_is_expected() { - debug!("Not as polymorphic!"); - return Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - } else { - debug!("Overly polymorphic!"); - return Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); } } - } - debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + debug!("higher_ranked_sub: OK result={}", + result.repr(self.tcx())); - return Ok(result); + Ok(result) + }); } fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> where T : HigherRankedCombineable<'tcx> { - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); - let (a_with_fresh, a_map) = - 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( - span, HigherRankedType, b); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("lub result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), &a_map, r)); - - debug!("lub({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let span = self.trace().origin.span(); + let (a_with_fresh, a_map) = + 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( + span, HigherRankedType, b); + + // Collect constraints. + let result0 = + try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + let 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 result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), &a_map, r)); + + debug!("lub({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(result1) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -174,7 +182,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation @@ -215,47 +223,49 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C debug!("{}.higher_ranked_glb({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - // Make a mark so we can examine "all bindings that were + // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // 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); - let (b_with_fresh, b_map) = - 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!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("glb result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in fn_ty0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), - &a_map, a_vars.as_slice(), b_vars.as_slice(), - r)); - - debug!("glb({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|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); + let (b_with_fresh, b_map) = + 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!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("glb result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in fn_ty0 if possible + 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, + new_vars.as_slice(), + &a_map, a_vars.as_slice(), b_vars.as_slice(), + r)); + + debug!("glb({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(result1) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -267,7 +277,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); let mut a_r = None; let mut b_r = None; @@ -443,3 +453,86 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> })) } +impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec { + self.region_vars.tainted(&snapshot.region_vars_snapshot, r) + } + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec + { + /*! + * Returns the set of region variables that do not affect any + * types/regions which existed before `snapshot` was + * started. This is used in the sub/lub/glb computations. The + * idea here is that when we are computing lub/glb of two + * regions, we sometimes create intermediate region variables. + * Those region variables may touch some of the skolemized or + * other "forbidden" regions we created to replace bound + * regions, but they don't really represent an "external" + * constraint. + * + * However, sometimes fresh variables are created for other + * purposes too, and those *may* represent an external + * constraint. In particular, when a type variable is + * instantiated, we create region variables for all the + * regions that appear within, and if that type variable + * pre-existed the snapshot, then those region variables + * represent external constraints. + * + * An example appears in the unit test + * `sub_free_bound_false_infer`. In this test, we want to + * know whether + * + * ```rust + * fn(_#0t) <: for<'a> fn(&'a int) + * ``` + * + * Note that the subtype has a type variable. Because the type + * variable can't be instantiated with a region that is bound + * in the fn signature, this comparison ought to fail. But if + * we're not careful, it will succeed. + * + * The reason is that when we walk through the subtyping + * algorith, we begin by replacing `'a` with a skolemized + * variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This + * can be made true by unifying `_#0t` with `&'0 int`. In the + * process, we create a fresh variable for the skolemized + * region, `'$0`, and hence we have that `_#0t == &'$0 + * int`. However, because `'$0` was created during the sub + * computation, if we're not careful we will erroneously + * assume it is one of the transient region variables + * representing a lub/glb internally. Not good. + * + * To prevent this, we check for type variables which were + * unified during the snapshot, and say that any region + * variable created during the snapshot but which finds its + * way into a type variable is considered to "escape" the + * snapshot. + */ + + let mut region_vars = + self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); + + let escaping_types = + self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); + + let escaping_region_vars: FnvHashSet<_> = + escaping_types + .iter() + .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter()) + .collect(); + + region_vars.retain(|®ion_vid| { + let r = ty::ReInfer(ty::ReVar(region_vid)); + !escaping_region_vars.contains(&r) + }); + + debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}", + region_vars.repr(self.tcx), + escaping_types.repr(self.tcx)); + + region_vars + } +} diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 14153907ee764..4ad7af713bd2c 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -520,6 +520,7 @@ 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, int_snapshot: unify::Snapshot, @@ -629,16 +630,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce() -> Result { - self.commit_unconditionally(move || self.try(move || f())) + self.commit_unconditionally(move || self.try(move |_| f())) } /// Execute `f`, unroll bindings on panic pub fn try(&self, f: F) -> Result where - F: FnOnce() -> Result + F: FnOnce(&CombinedSnapshot) -> Result { debug!("try()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); debug!("try() -- r.is_ok() = {}", r.is_ok()); match r { Ok(_) => { @@ -821,7 +822,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(&t)) } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -830,7 +831,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn trait_ref_to_string(&self, t: &Rc>) -> String { - let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t); + let t = self.resolve_type_vars_if_possible(&**t); trait_ref_to_string(self.tcx, &t) } @@ -867,35 +868,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } - } - - pub fn resolve_type_vars_in_trait_ref_if_possible(&self, - trait_ref: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { - // make up a dummy type just to reuse/abuse the resolve machinery - let dummy0 = ty::mk_trait(self.tcx, - (*trait_ref).clone(), - ty::region_existential_bound(ty::ReStatic)); - let dummy1 = self.resolve_type_vars_if_possible(dummy0); - match dummy1.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => { - (*principal).clone() - } - _ => { - self.tcx.sess.bug( - format!("resolve_type_vars_if_possible() yielded {} \ - when supplied with {}", - self.ty_to_string(dummy0), - self.ty_to_string(dummy1)).as_slice()); - } - } + pub fn resolve_type_vars_if_possible>(&self, value: &T) -> T { + let mut r = resolve::DeepTypeResolver::new(self); + value.fold_with(&mut r) } // [Note-Type-error-reporting] @@ -929,9 +904,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty); - let resolved_expected = expected_ty.map(|e_ty| { - self.resolve_type_vars_if_possible(e_ty) - }); + let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); match resolved_expected { Some(t) if ty::type_is_error(t) => (), @@ -958,7 +931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: Option<&ty::type_err<'tcx>>) where M: FnOnce(String) -> String, { - let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is ty_err. if ty::type_is_error(actual_ty) { diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index ca2860ae6b37c..fef87c920679e 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -81,7 +81,6 @@ impl Copy for TwoRegions {} pub enum UndoLogEntry { OpenSnapshot, CommitedSnapshot, - Mark, AddVar(RegionVid), AddConstraint(Constraint), AddVerify(uint), @@ -225,19 +224,11 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> { } #[deriving(Show)] +#[allow(missing_copy_implementations)] pub struct RegionSnapshot { length: uint } -impl Copy for RegionSnapshot {} - -#[deriving(Show)] -pub struct RegionMark { - length: uint -} - -impl Copy for RegionMark {} - impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { RegionVarBindings { @@ -266,13 +257,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { RegionSnapshot { length: length } } - pub fn mark(&self) -> RegionMark { - let length = self.undo_log.borrow().len(); - debug!("RegionVarBindings: mark({})", length); - self.undo_log.borrow_mut().push(Mark); - RegionMark { length: length } - } - pub fn commit(&self, snapshot: RegionSnapshot) { debug!("RegionVarBindings: commit({})", snapshot.length); assert!(self.undo_log.borrow().len() > snapshot.length); @@ -296,7 +280,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { OpenSnapshot => { panic!("Failure to observe stack discipline"); } - Mark | CommitedSnapshot => { } + CommitedSnapshot => { } AddVar(vid) => { let mut var_origins = self.var_origins.borrow_mut(); var_origins.pop().unwrap(); @@ -597,8 +581,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { ReInfer(ReVar(c)) } - pub fn vars_created_since_mark(&self, mark: RegionMark) - -> Vec + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) + -> Vec { self.undo_log.borrow() .slice_from(mark.length) @@ -613,7 +597,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// Computes all regions that have been related to `r0` in any way since the mark `mark` was /// made---`r0` itself will be the first entry. This is used when checking whether skolemized /// regions are being improperly related to other regions. - pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec { + pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx)); let _indenter = indenter(); @@ -668,7 +652,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } &AddCombination(..) | - &Mark | &AddVar(..) | &OpenSnapshot | &CommitedSnapshot => { diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index eaf363ffc74c2..5edf78a474b62 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -258,3 +258,38 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +/// DEEP TYPE RESOLVER +/// +/// This kind of resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct DeepTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> { + DeepTypeResolver { infcx: infcx } + } +} + +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !ty::type_has_ty_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty_fold::super_fold_ty(self, t0) + } + } +} + + diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 766e930486ca2..0d7f542535c2f 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -13,7 +13,9 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use middle::ty::{mod, Ty}; +use std::cmp::min; use std::mem; +use std::uint; use util::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { @@ -78,7 +80,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// Precondition: neither `a` nor `b` are known. pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - if a != b { self.relations(a).push((dir, b)); self.relations(b).push((dir.opposite(), a)); @@ -151,6 +152,49 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn commit(&mut self, s: Snapshot) { self.values.commit(s.snapshot); } + + pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { + /*! + * Find the set of type variables that existed *before* `s` + * but which have only been unified since `s` started, and + * return the types with which they were unified. So if we had + * a type variable `V0`, then we started the snapshot, then we + * created a type variable `V1`, unifed `V0` with `T0`, and + * unified `V1` with `T1`, this function would return `{T0}`. + */ + + let mut new_elem_threshold = uint::MAX; + let mut escaping_types = Vec::new(); + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); + for action in actions_since_snapshot.iter() { + match *action { + sv::UndoLog::NewElem(index) => { + // if any new variables were created during the + // snapshot, remember the lower index (which will + // always be the first one we see). Note that this + // action must precede those variables being + // specified. + new_elem_threshold = min(new_elem_threshold, index); + debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); + } + + sv::UndoLog::Other(SpecifyVar(vid, _)) => { + if vid.index < new_elem_threshold { + // quick check to see if this variable was + // created since the snapshot started or not. + let escaping_type = self.probe(vid).unwrap(); + escaping_types.push(escaping_type); + } + debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold); + } + + _ => { } + } + } + + escaping_types + } } impl<'tcx> sv::SnapshotVecDelegate,UndoEntry> for Delegate { diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4877512ce5816..3da9fba0ee89d 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -790,6 +790,17 @@ impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> } } +pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec + where T : TypeFoldable<'tcx> +{ + let mut vec = Vec::new(); + { + let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r }); + value.fold_with(&mut folder); + } + vec +} + impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> ty::Region, { diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index e80e8dc535104..749c39d7a6b92 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -23,7 +23,7 @@ use self::UndoLog::*; use std::mem; #[deriving(PartialEq)] -enum UndoLog { +pub enum UndoLog { /// Indicates where a snapshot started. OpenSnapshot, @@ -113,6 +113,12 @@ impl> SnapshotVec { Snapshot { length: length } } + pub fn actions_since_snapshot(&self, + snapshot: &Snapshot) + -> &[UndoLog] { + self.undo_log[snapshot.length..] + } + fn assert_open_snapshot(&self, snapshot: &Snapshot) { // Or else there was a failure to follow a stack discipline: assert!(self.undo_log.len() > snapshot.length); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 943650ce8a63b..14d36432afaa8 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -502,6 +502,26 @@ fn sub_free_bound_false_infer() { }) } +#[test] +fn lub_free_bound_infer() { + //! Test result of: + //! + //! LUB(fn(_#1), for<'b> fn(&'b int)) + //! + //! This should yield `fn(&'_ int)`. We check + //! that it yields `fn(&'x int)` for some free `'x`, + //! anyhow. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }); +} + #[test] fn lub_bound_bound() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { @@ -605,6 +625,28 @@ fn glb_bound_free() { }) } +#[test] +fn glb_bound_free_infer() { + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_infer1 = env.infcx.next_ty_var(); + + // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int), + // which should yield for<'b> fn(&'b int) -> int + env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + + // as a side-effect, computing GLB should unify `_` with + // `&'_ int` + let t_resolve1 = env.infcx.shallow_resolve(t_infer1); + match t_resolve1.sty { + ty::ty_rptr(..) => { } + _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); } + } + }) +} + #[test] fn glb_bound_static() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index e3fec2c8b1df2..a4fee8573c592 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -196,7 +196,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("found object type {}", kind); let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0); - let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty); + let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { @@ -206,7 +206,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("input_tys {}", input_tys.repr(tcx)); let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1); - let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty); + let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d97a9c9e39b19..ac7bc81b2f874 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -100,7 +100,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr.repr(fcx.tcx()), self_expr.repr(fcx.tcx())); - let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty); + let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id)); Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index def82ecd6c85b..ea33153f3b1af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1638,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn default_diverging_type_variables_to_nil(&self) { for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() { - if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) { + if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) { demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); } } @@ -2486,7 +2486,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let method_type = match method { Some(ref method) => method.ty, None => { - let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type); + let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type); if !ty::type_is_error(true_expr_type) { let ty_string = fcx.infcx().ty_to_string(true_expr_type); @@ -3976,7 +3976,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, vtable::select_new_fcx_obligations(fcx); debug!("ExprForLoop each item has type {}", - fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx())); + fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx())); let pcx = pat_ctxt { fcx: fcx, @@ -4371,11 +4371,11 @@ impl<'tcx> Expectation<'tcx> { } ExpectCastableToType(t) => { ExpectCastableToType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } ExpectHasType(t) => { ExpectHasType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } } } diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 415a3d53fb284..664705c89ab2a 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -331,7 +331,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref); + fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); fcx.tcx().sess.span_err( obligation.cause.span, format!( @@ -341,8 +341,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); + let a = fcx.infcx().resolve_type_vars_if_possible(&a); + let b = fcx.infcx().resolve_type_vars_if_possible(&b); fcx.tcx().sess.span_err( obligation.cause.span, format!( @@ -373,8 +373,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &**trait_ref); + fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); if !ty::type_is_error(trait_ref.self_ty()) { fcx.tcx().sess.span_err( obligation.cause.span, @@ -387,8 +386,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); + let a = fcx.infcx().resolve_type_vars_if_possible(&a); + let b = fcx.infcx().resolve_type_vars_if_possible(&b); let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err(); fcx.tcx().sess.span_err( obligation.cause.span, @@ -413,10 +412,10 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**expected_trait_ref); let actual_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**actual_trait_ref); if !ty::type_is_error(actual_trait_ref.self_ty()) { fcx.tcx().sess.span_err( @@ -443,7 +442,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let trait_ref = match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref) + fcx.infcx().resolve_type_vars_if_possible(&**trait_ref) } _ => { fcx.tcx().sess.span_bug( diff --git a/src/test/compile-fail/bad-match.rs b/src/test/compile-fail/bad-match.rs index 39c3ed3e2a3d2..728b577df1dd4 100644 --- a/src/test/compile-fail/bad-match.rs +++ b/src/test/compile-fail/bad-match.rs @@ -14,3 +14,6 @@ fn main() { let int x = 5; match x; } + +fn main() { +} From eb6ea5d49b4eb21278d6ecdfa472f2cd90d379d0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Dec 2014 12:27:27 -0500 Subject: [PATCH 03/24] Cleanup type resolution to use type folding infrastructure and not have such a silly over-engineered interface. --- src/librustc/middle/infer/coercion.rs | 16 +- src/librustc/middle/infer/mod.rs | 68 +++--- src/librustc/middle/infer/resolve.rs | 322 ++++++------------------- src/librustc_typeck/check/_match.rs | 41 ++-- src/librustc_typeck/check/demand.rs | 9 +- src/librustc_typeck/check/regionck.rs | 8 +- src/librustc_typeck/check/writeback.rs | 29 +-- src/librustc_typeck/coherence/mod.rs | 88 ++----- 8 files changed, 155 insertions(+), 426 deletions(-) diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 43d99ecb427a7..edb544aca6d99 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -60,10 +60,9 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use super::{CoerceResult, resolve_type, Coercion}; +use super::{CoerceResult, Coercion}; use super::combine::{CombineFields, Combine}; use super::sub::Sub; -use super::resolve::try_resolve_tvar_shallow; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; @@ -197,18 +196,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { pub fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(&ty::sty<'tcx>) -> T, { - match resolve_type(self.get_ref().infcx, None, - a, try_resolve_tvar_shallow) { - Ok(t) => { - f(&t.sty) - } - Err(e) => { - self.get_ref().infcx.tcx.sess.span_bug( - self.get_ref().trace.origin.span(), - format!("failed to resolve even without \ - any force options: {}", e).as_slice()); - } - } + f(&self.get_ref().infcx.shallow_resolve(a).sty) } // ~T -> &T or &mut T -> &T (including where T = [U] or str) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4ad7af713bd2c..0c70d2081196d 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -19,13 +19,6 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use self::fixup_err::*; pub use middle::ty::IntVarValue; -pub use self::resolve::resolve_and_force_all_but_regions; -pub use self::resolve::{force_all, not_regions}; -pub use self::resolve::{force_ivar}; -pub use self::resolve::{force_tvar, force_rvar}; -pub use self::resolve::{resolve_ivar, resolve_all}; -pub use self::resolve::{resolve_nested_tvar}; -pub use self::resolve::{resolve_rvar}; pub use self::skolemize::TypeSkolemizer; use middle::subst; @@ -47,7 +40,6 @@ use util::ppaux::{trait_ref_to_string, Repr}; use self::coercion::Coerce; use self::combine::{Combine, CombineFields}; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::resolve::{resolver}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; @@ -453,22 +445,6 @@ pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, }) } -// See comment on the type `resolve_state` below -pub fn resolve_type<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - span: Option, - a: Ty<'tcx>, - modes: uint) - -> fres> { - let mut resolver = resolver(cx, modes, span); - cx.commit_unconditionally(|| resolver.resolve_type_chk(a)) -} - -pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint) - -> fres { - let mut resolver = resolver(cx, modes, None); - resolver.resolve_region_chk(r) -} - trait then<'tcx> { fn then(&self, f: F) -> Result> where T: Clone, @@ -835,20 +811,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref_to_string(self.tcx, &t) } - pub fn contains_unbound_type_variables(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } - } - pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::ty_infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. self.type_variables.borrow() .probe(v) + .map(|t| self.shallow_resolve(t)) .unwrap_or(typ) } @@ -869,10 +846,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn resolve_type_vars_if_possible>(&self, value: &T) -> T { - let mut r = resolve::DeepTypeResolver::new(self); + /*! + * Where possible, replaces type/int/float variables in + * `value` with their final value. Note that region variables + * are unaffected. If a type variable has not been unified, it + * is left as is. This is an idempotent operation that does + * not affect inference state in any way and so you can do it + * at will. + */ + + let mut r = resolve::OpportunisticTypeResolver::new(self); value.fold_with(&mut r) } + pub fn fully_resolve>(&self, value: &T) -> fres { + /*! + * Attempts to resolve all type/region variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) + } + // [Note-Type-error-reporting] // An invariant is that anytime the expected or actual type is ty_err (the special // error type, meaning that an error occurred when typechecking this expression), diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 5edf78a474b62..12400de31ed9e 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -8,288 +8,108 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Resolution is the process of removing type variables and replacing -// them with their inferred values. Unfortunately our inference has -// become fairly complex and so there are a number of options to -// control *just how much* you want to resolve and how you want to do -// it. -// -// # Controlling the scope of resolution -// -// The options resolve_* determine what kinds of variables get -// resolved. Generally resolution starts with a top-level type -// variable; we will always resolve this. However, once we have -// resolved that variable, we may end up with a type that still -// contains type variables. For example, if we resolve `` we may -// end up with something like `[]`. If the option -// `resolve_nested_tvar` is passed, we will then go and recursively -// resolve ``. -// -// The options `resolve_rvar` controls whether we resolve region -// variables. The options `resolve_fvar` and `resolve_ivar` control -// whether we resolve floating point and integral variables, -// respectively. -// -// # What do if things are unconstrained -// -// Sometimes we will encounter a variable that has no constraints, and -// therefore cannot sensibly be mapped to any particular result. By -// default, we will leave such variables as is (so you will get back a -// variable in your result). The options force_* will cause the -// resolution to fail in this case instead, except for the case of -// integral variables, which resolve to `int` if forced. -// -// # resolve_all and force_all -// -// The options are a bit set, so you can use the *_all to resolve or -// force all kinds of variables (including those we may add in the -// future). If you want to resolve everything but one type, you are -// probably better off writing `resolve_all - resolve_ivar`. - -#![allow(non_upper_case_globals)] - -use super::{fixup_err, fres, InferCtxt}; -use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; - -use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{IntType, UintType}; +use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty}; use middle::ty::{mod, Ty}; -use middle::ty_fold; -use syntax::codemap::Span; -use util::ppaux::{Repr, ty_to_string}; +use middle::ty_fold::{mod, TypeFoldable}; +use util::ppaux::Repr; -pub const resolve_nested_tvar: uint = 0b0000000001; -pub const resolve_rvar: uint = 0b0000000010; -pub const resolve_ivar: uint = 0b0000000100; -pub const resolve_fvar: uint = 0b0000001000; -pub const resolve_all: uint = 0b0000001111; -pub const force_tvar: uint = 0b0000100000; -pub const force_rvar: uint = 0b0001000000; -pub const force_ivar: uint = 0b0010000000; -pub const force_fvar: uint = 0b0100000000; -pub const force_all: uint = 0b0111100000; - -pub const not_regions: uint = !(force_rvar | resolve_rvar); - -pub const try_resolve_tvar_shallow: uint = 0; -pub const resolve_and_force_all_but_regions: uint = - (resolve_all | force_all) & not_regions; +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC TYPE RESOLVER -pub struct ResolveState<'a, 'tcx: 'a> { +/// The opportunistic type resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - err: Option, - type_depth: uint, } -pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - _: Option) - -> ResolveState<'a, 'tcx> { - ResolveState { - infcx: infcx, - modes: modes, - err: None, - type_depth: 0, +impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { + OpportunisticTypeResolver { infcx: infcx } } } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_type(t) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - self.resolve_region(r) - } -} - -impl<'a, 'tcx> ResolveState<'a, 'tcx> { - pub fn should(&mut self, mode: uint) -> bool { - (self.modes & mode) == mode - } - - pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres> { - self.err = None; - - debug!("Resolving {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - self.modes); - - // n.b. This is a hokey mess because the current fold doesn't - // allow us to pass back errors in any useful way. - - let rty = self.resolve_type(typ); - match self.err { - None => { - debug!("Resolved {} to {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - ty_to_string(self.infcx.tcx, rty), - self.modes); - return Ok(rty); - } - Some(e) => { - return Err(e); - } - } - } - - pub fn resolve_region_chk(&mut self, - orig: ty::Region) - -> fres { - self.err = None; - let resolved = self.resolve_region(orig); - match self.err { - None => Ok(resolved), - Some(e) => Err(e) - } - } - - pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_type({})", typ.repr(self.infcx.tcx)); - - if !ty::type_needs_infer(typ) { - return typ; - } - - if self.type_depth > 0 && !self.should(resolve_nested_tvar) { - return typ; - } - - match typ.sty { - ty::ty_infer(TyVar(vid)) => { - self.resolve_ty_var(vid) - } - ty::ty_infer(IntVar(vid)) => { - self.resolve_int_var(vid) - } - ty::ty_infer(FloatVar(vid)) => { - self.resolve_float_var(vid) - } - _ => { - if self.modes & resolve_all == 0 { - // if we are only resolving top-level type - // variables, and this is not a top-level type - // variable, then shortcircuit for efficiency - typ - } else { - self.type_depth += 1; - let result = ty_fold::super_fold_ty(self, typ); - self.type_depth -= 1; - result - } - } - } - } - - pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { - debug!("Resolve_region({})", orig.repr(self.infcx.tcx)); - match orig { - ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), - _ => orig - } - } - - pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region { - if !self.should(resolve_rvar) { - return ty::ReInfer(ty::ReVar(rid)); - } - self.infcx.region_vars.resolve_var(rid) - } - - pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> { - let tcx = self.infcx.tcx; - let tv = self.infcx.type_variables.borrow(); - match tv.probe(vid) { - Some(t) => { - self.resolve_type(t) - } - None => { - if self.should(force_tvar) { - self.err = Some(unresolved_ty(vid)); - } - ty::mk_var(tcx, vid) - } - } - } - - pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> { - if !self.should(resolve_ivar) { - return ty::mk_int_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.int_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(IntType(t)) => ty::mk_mach_int(t), - Some(UintType(t)) => ty::mk_mach_uint(t), - None => { - if self.should(force_ivar) { - // As a last resort, emit an error. - self.err = Some(unresolved_int_ty(vid)); - } - ty::mk_int_var(self.infcx.tcx, vid) - } - } - } - - pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> { - if !self.should(resolve_fvar) { - return ty::mk_float_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.float_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(t) => ty::mk_mach_float(t), - None => { - if self.should(force_fvar) { - // As a last resort, emit an error. - self.err = Some(unresolved_float_ty(vid)); - } - ty::mk_float_var(self.infcx.tcx, vid) - } + if !ty::type_has_ty_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty_fold::super_fold_ty(self, t0) } } } /////////////////////////////////////////////////////////////////////////// -/// DEEP TYPE RESOLVER -/// -/// This kind of resolver can be used at any time. It simply replaces -/// type variables that have been unified with the things they have -/// been unified with (similar to `shallow_resolve`, but deep). This is -/// useful for printing messages etc but also required at various -/// points for correctness. -pub struct DeepTypeResolver<'a, 'tcx:'a> { - infcx: &'a InferCtxt<'a, 'tcx>, +// FULL TYPE RESOLUTION + +/// Full type resolution replaces all type and region variables with +/// their concrete results. If any variable cannot be replaced (never unified, etc) +/// then an `Err` result is returned. +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> fres + where T : TypeFoldable<'tcx> +{ + let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let result = value.fold_with(&mut full_resolver); + match full_resolver.err { + None => Ok(result), + Some(e) => Err(e), + } } -impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> { - DeepTypeResolver { infcx: infcx } - } +// N.B. This type is not public because the protocol around checking the +// `err` field is not enforcable otherwise. +struct FullTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + err: Option, } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_has_ty_infer(t) { + if !ty::type_needs_infer(t) { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve(t); - ty_fold::super_fold_ty(self, t0) + let t = self.infcx.shallow_resolve(t); + match t.sty { + ty::ty_infer(ty::TyVar(vid)) => { + self.err = Some(unresolved_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::IntVar(vid)) => { + self.err = Some(unresolved_int_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::FloatVar(vid)) => { + self.err = Some(unresolved_float_ty(vid)); + ty::mk_err() + } + ty::ty_infer(_) => { + self.infcx.tcx.sess.bug( + format!("Unexpected type in full type resolver: {}", + t.repr(self.infcx.tcx))[]); + } + _ => { + ty_fold::super_fold_ty(self, t) + } + } } } -} + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid), + _ => r, + } + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b88da5d9387d3..b31683219f1cd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def; -use middle::infer::{mod, resolve}; +use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; @@ -143,11 +143,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatRegion(ref inner) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = infer::resolve_type( - fcx.infcx(), Some(pat.span), - expected, resolve::try_resolve_tvar_shallow) - .ok() - .and_then(|t| ty::deref(t, true)) + let mutbl = + ty::deref(fcx.infcx().shallow_resolve(expected), true) .map_or(ast::MutImmutable, |mt| mt.mutbl); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; @@ -214,23 +211,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, inner: &ast::Pat) -> bool { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - match infer::resolve_type( - fcx.infcx(), Some(span), - expected, resolve::try_resolve_tvar_shallow) { - Ok(t) if pat_is_binding(&tcx.def_map, inner) => { - ty::deref(t, true).map_or(true, |mt| match mt.ty.sty { - ty::ty_trait(_) => { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. - span_err!(tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - fcx.infcx().ty_to_string(t)); - false - } - _ => true - }) - } - _ => true + if pat_is_binding(&tcx.def_map, inner) { + let expected = fcx.infcx().shallow_resolve(expected); + ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty { + ty::ty_trait(_) => { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box", an error. + span_err!(tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", + fcx.infcx().ty_to_string(expected)); + false + } + _ => true + }) + } else { + true } } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 980097eaead99..9af9eaf75f5a5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -12,8 +12,6 @@ use check::FnCtxt; use middle::ty::{mod, Ty}; use middle::infer; -use middle::infer::resolve_type; -use middle::infer::resolve::try_resolve_tvar_shallow; use std::result::Result::{Err, Ok}; use syntax::ast; @@ -63,12 +61,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, debug!("demand::coerce(expected = {}, expr_ty = {})", expected.repr(fcx.ccx.tcx), expr_ty.repr(fcx.ccx.tcx)); - let expected = if ty::type_needs_infer(expected) { - resolve_type(fcx.infcx(), - None, - expected, - try_resolve_tvar_shallow).unwrap_or(expected) - } else { expected }; + let expected = fcx.infcx().resolve_type_vars_if_possible(&expected); match fcx.mk_assignty(expr, expr_ty, expected) { Ok(()) => { /* ok */ } Err(ref err) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bfa3c384da7b2..ad6ba0a1d5571 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -124,8 +124,6 @@ use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty, MethodCall}; -use middle::infer::resolve_and_force_all_but_regions; -use middle::infer::resolve_type; use middle::infer; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; @@ -307,11 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// of b will be `&.int` and then `*b` will require that `` be bigger than the let and /// the `*b` expression, so we will effectively resolve `` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) { - Ok(t) => t, - Err(_) => ty::mk_err() - } + self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) } /// Try to resolve the type for the given node. diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8d94cf5dd5e96..b73381966e8dc 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -19,8 +19,6 @@ use middle::def; use middle::pat_util; use middle::ty::{mod, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; -use middle::infer::{force_all, resolve_all, resolve_region}; -use middle::infer::resolve_type; use middle::infer; use write_substs_to_tcx; use write_ty_to_tcx; @@ -337,8 +335,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve>(&self, t: &T, reason: ResolveReason) -> T { - t.resolve_in(&mut Resolver::new(self.fcx, reason)) + fn resolve>(&self, t: &T, reason: ResolveReason) -> T { + t.fold_with(&mut Resolver::new(self.fcx, reason)) } } @@ -375,19 +373,6 @@ impl ResolveReason { } } -/////////////////////////////////////////////////////////////////////////// -// Convenience methods for resolving different kinds of things. - -trait ResolveIn<'tcx> { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self; -} - -impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T { - self.fold_with(resolver) - } -} - /////////////////////////////////////////////////////////////////////////// // The Resolver. This is the type folding engine that detects // unresolved types and so forth. @@ -465,13 +450,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) { - return t; - } - - match resolve_type(self.infcx, None, t, resolve_all | force_all) { + match self.infcx.fully_resolve(&t) { Ok(t) => t, Err(e) => { + debug!("Resolver::fold_ty: input type `{}` not fully resolvable", + t.repr(self.tcx)); self.report_error(e); ty::mk_err() } @@ -479,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match resolve_region(self.infcx, r, resolve_all | force_all) { + match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(e) => { self.report_error(e); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a55f3c6191940..8ed0ac98e1eae 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -26,12 +26,13 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; -use middle::ty::{type_is_ty_var}; +use middle::ty::{ty_closure}; +use middle::subst::Subst; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use middle::infer::{new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -52,80 +53,35 @@ mod orphan; mod overlap; mod unsafety; -fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option> { - let resolved_type = match resolve_type(inference_context, - Some(span), - original_type, - resolve_ivar) { - Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type, - _ => { - inference_context.tcx.sess.span_fatal(span, - "the type of this value must be known in order \ - to determine the base type"); - } - }; - - match resolved_type.sty { - ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => { - debug!("(getting base type) found base type"); - Some(resolved_type) +// Returns the def ID of the base type, if there is one. +fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) + -> Option { + match ty.sty { + ty_enum(def_id, _) | + ty_struct(def_id, _) => { + Some(def_id) } - _ if ty::type_is_trait(resolved_type) => { - debug!("(getting base type) found base type (trait)"); - Some(resolved_type) + ty_trait(ref t) => { + Some(t.principal.def_id) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | + ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { - debug!("(getting base type) no base type; found {}", - original_type.sty); None } - ty_trait(..) => panic!("should have been caught") - } -} -// Returns the def ID of the base type, if there is one. -fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option { - match get_base_type(inference_context, span, original_type) { - None => None, - Some(base_type) => { - match base_type.sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _, _) => { - Some(def_id) - } - ty_ptr(ty::mt {ty, ..}) | - ty_rptr(_, ty::mt {ty, ..}) | - ty_uniq(ty) => { - match ty.sty { - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } - } - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } + ty_infer(..) | ty_unboxed_closure(..) => { + // `ty` comes from a user declaration so we should only expect types + // that the user can type + inference_context.tcx.sess.span_bug( + span, + format!("coherence encountered unexpected type searching for base type: {}", + ty.repr(inference_context.tcx))[]); } } } From 5a6a26acd616ba87129ad1f50ba64d66ade82bc5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 Dec 2014 13:58:38 -0500 Subject: [PATCH 04/24] Delete tests that passed in error. We currently do not support a Clone impl for fn pointer types including bound regions, unfortunately. --- src/test/run-pass/issue-10501.rs | 14 ------------- src/test/run-pass/issue-12741.rs | 35 -------------------------------- 2 files changed, 49 deletions(-) delete mode 100644 src/test/run-pass/issue-10501.rs delete mode 100644 src/test/run-pass/issue-12741.rs diff --git a/src/test/run-pass/issue-10501.rs b/src/test/run-pass/issue-10501.rs deleted file mode 100644 index 78f125398edcb..0000000000000 --- a/src/test/run-pass/issue-10501.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -pub type Foo = fn(&int) -> (); -#[deriving(Clone)] -enum Baz { Bar(Foo) } -fn main() {} diff --git a/src/test/run-pass/issue-12741.rs b/src/test/run-pass/issue-12741.rs deleted file mode 100644 index e41613b4ae305..0000000000000 --- a/src/test/run-pass/issue-12741.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -#[deriving(Clone)] -pub struct Foo { - f: fn(char, |char| -> char) -> char -} - -impl Foo { - fn bar(&self) -> char { - ((*self).f)('a', |c: char| c) - } -} - -fn bla(c: char, cb: |char| -> char) -> char { - cb(c) -} - -pub fn make_foo() -> Foo { - Foo { - f: bla - } -} - -fn main() { - let a = make_foo(); - assert_eq!(a.bar(), 'a'); -} From 7be059ffcd640096911b62b9135d2ffbf3a05abc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 2 Dec 2014 13:59:27 -0500 Subject: [PATCH 05/24] Propagate expected type more widely so that we can rewrite the issue-14039 test in a more natural way. Previously the "type we will cast to" was hidden unless it was an integer. --- src/librustc_typeck/check/mod.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ea33153f3b1af..eabf52c2cc8b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1390,13 +1390,7 @@ fn check_cast(fcx: &FnCtxt, let t_1 = fcx.to_ty(t); let t_1 = structurally_resolved_type(fcx, span, t_1); - if ty::type_is_scalar(t_1) { - // Supply the type as a hint so as to influence integer - // literals and other things that might care. - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)) - } else { - check_expr(fcx, e) - } + check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)); let t_e = fcx.expr_ty(e); From ff35eeb80a30ffbe3bcc334ed8accb97937676f4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Dec 2014 11:12:48 -0500 Subject: [PATCH 06/24] Recycle skolemization counts and add some comments. --- .../middle/infer/higher_ranked/mod.rs | 4 ++- .../middle/infer/region_inference/mod.rs | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 0a2049bef48f2..d462c223bc65b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -76,7 +76,9 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // fresh concrete region. let (b_prime, skol_map) = { replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = self.infcx().region_vars.new_skolemized(br); + let skol = + self.infcx().region_vars.new_skolemized( + br, &snapshot.region_vars_snapshot); debug!("Bound region {} skolemized to {}", bound_region_to_string(self.tcx(), "", false, br), skol); diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index fef87c920679e..d34373e66a1e0 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -226,7 +226,8 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> { #[deriving(Show)] #[allow(missing_copy_implementations)] pub struct RegionSnapshot { - length: uint + length: uint, + skolemization_count: uint, } impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { @@ -254,7 +255,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let length = self.undo_log.borrow().len(); debug!("RegionVarBindings: start_snapshot({})", length); self.undo_log.borrow_mut().push(OpenSnapshot); - RegionSnapshot { length: length } + RegionSnapshot { length: length, skolemization_count: self.skolemization_count.get() } } pub fn commit(&self, snapshot: RegionSnapshot) { @@ -268,6 +269,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } else { (*undo_log)[snapshot.length] = CommitedSnapshot; } + self.skolemization_count.set(snapshot.skolemization_count); } pub fn rollback_to(&self, snapshot: RegionSnapshot) { @@ -306,6 +308,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } let c = undo_log.pop().unwrap(); assert!(c == OpenSnapshot); + self.skolemization_count.set(snapshot.skolemization_count); } pub fn num_vars(&self) -> uint { @@ -324,7 +327,25 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { return vid; } - pub fn new_skolemized(&self, br: ty::BoundRegion) -> Region { + /// Creates a new skolemized region. Skolemized regions are fresh + /// regions used when performing higher-ranked computations. They + /// must be used in a very particular way and are never supposed + /// to "escape" out into error messages or the code at large. + /// + /// The idea is to always create a snapshot. Skolemized regions + /// can be created in the context of this snapshot, but once the + /// snapshot is commited or rolled back, their numbers will be + /// recycled, so you must be finished with them. See the extensive + /// comments in `higher_ranked.rs` to see how it works (in + /// particular, the subtyping comparison). + /// + /// The `snapshot` argument to this function is not really used; + /// it's just there to make it explicit which snapshot bounds the + /// skolemized region that results. + pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { + assert!(self.in_snapshot()); + assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); + let sc = self.skolemization_count.get(); self.skolemization_count.set(sc + 1); ReInfer(ReSkolemized(sc, br)) From 885f7ee12ec568ea2c3094407f8b1a94628b3853 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Dec 2014 18:09:50 -0500 Subject: [PATCH 07/24] Extract skolemize_regions() helper function. --- .../middle/infer/higher_ranked/mod.rs | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index d462c223bc65b..c1320b6042ab0 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -74,17 +74,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Second, we instantiate each bound region in the supertype with a // fresh concrete region. - let (b_prime, skol_map) = { - replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = - self.infcx().region_vars.new_skolemized( - br, &snapshot.region_vars_snapshot); - debug!("Bound region {} skolemized to {}", - bound_region_to_string(self.tcx(), "", false, br), - skol); - skol - }) - }; + let (b_prime, skol_map) = skolemize_regions(self.infcx(), b, snapshot); debug!("a_prime={}", a_prime.repr(self.tcx())); debug!("b_prime={}", b_prime.repr(self.tcx())); @@ -538,3 +528,23 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { region_vars } } + +fn skolemize_regions<'a,'tcx,HR>(infcx: &InferCtxt<'a,'tcx>, + value: &HR, + snapshot: &CombinedSnapshot) + -> (HR, FnvHashMap) + where HR : HigherRankedFoldable<'tcx> +{ + replace_late_bound_regions(infcx.tcx, value, |br, _| { + let skol = + infcx.region_vars.new_skolemized( + br, + &snapshot.region_vars_snapshot); + + debug!("Bound region {} skolemized to {}", + bound_region_to_string(infcx.tcx, "", false, br), + skol); + + skol + }) +} From 1b24602ca083cc20169190556a51066af0438049 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Dec 2014 18:27:04 -0500 Subject: [PATCH 08/24] Extract leak check into a distinct subroutine. --- .../middle/infer/higher_ranked/mod.rs | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index c1320b6042ab0..ef8c2f414acf4 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -84,30 +84,17 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); - for (&skol_br, &skol) in skol_map.iter() { - let tainted = self.infcx().tainted_regions(snapshot, skol); - for tainted_region in tainted.iter() { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReInfer(ty::ReVar(ref vid)) => { - if new_vars.iter().any(|x| x == vid) { continue; } - } - _ => { - if *tainted_region == skol { continue; } - } - }; - - // A is not as polymorphic as B: + match leak_check(self.infcx(), &skol_map, snapshot) { + Ok(()) => { } + Err((skol_br, tainted_region)) => { if self.a_is_expected() { debug!("Not as polymorphic!"); return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, - *tainted_region)); + tainted_region)); } else { debug!("Overly polymorphic!"); return Err(ty::terr_regions_overly_polymorphic(skol_br, - *tainted_region)); + tainted_region)); } } } @@ -548,3 +535,30 @@ fn skolemize_regions<'a,'tcx,HR>(infcx: &InferCtxt<'a,'tcx>, skol }) } + +fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + skol_map: &FnvHashMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> +{ + let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map.iter() { + let tainted = infcx.tainted_regions(snapshot, skol); + for &tainted_region in tainted.iter() { + // Each skolemized should only be relatable to itself + // or new variables: + match tainted_region { + ty::ReInfer(ty::ReVar(vid)) => { + if new_vars.iter().any(|&x| x == vid) { continue; } + } + _ => { + if tainted_region == skol { continue; } + } + }; + + // A is not as polymorphic as B: + return Err((skol_br, tainted_region)); + } + } + Ok(()) +} From b3dcb85404aabd66a5765bb99aa46e24acede4dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Dec 2014 19:11:15 -0500 Subject: [PATCH 09/24] Fix a bug in the opt-in-copy work: it was failing to liberate the regions bound in the impl before searching for `Copy` implements for all fields, leading to problems in the "copyability check". Basically the copyability check would wind up looking for an impl of `for<'tcx> Foo<&'tcx T>`. The impl that exists however is `impl Copy for Foo` and the current rules do not consider that a match (something I would like to revise in a later PR). --- src/librustc_typeck/coherence/mod.rs | 14 ++++++++-- src/test/run-pass/hrtb-opt-in-copy.rs | 38 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/hrtb-opt-in-copy.rs diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 8ed0ac98e1eae..16a77315bd50b 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,6 +18,7 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; +use middle::region; use middle::subst::{mod, Subst}; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; @@ -26,8 +27,6 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; -use middle::ty::{ty_closure}; -use middle::subst::Subst; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; @@ -472,6 +471,17 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { impl_did.node); let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + // the self-type may have late-bound regions bound in the + // impl; liberate them. + let item_scope = region::CodeExtent::from_node_id(impl_did.node); + let self_type = + ty::liberate_late_bound_regions(tcx, + item_scope, + &ty::bind(self_type)).value; + + debug!("can_type_implement_copy(self_type={})", + self_type.repr(tcx)); + match ty::can_type_implement_copy(tcx, self_type, ¶m_env) { Ok(()) => {} Err(ty::FieldDoesNotImplementCopy(name)) => { diff --git a/src/test/run-pass/hrtb-opt-in-copy.rs b/src/test/run-pass/hrtb-opt-in-copy.rs new file mode 100644 index 0000000000000..b6bba363e7236 --- /dev/null +++ b/src/test/run-pass/hrtb-opt-in-copy.rs @@ -0,0 +1,38 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we handle binder levels correctly when checking whether a +// type can implement `Copy`. In particular, we had a bug where we failed to +// liberate the late-bound regions from the impl, and thus wound up +// searching for an impl of `for<'tcx> Foo<&'tcx T>`. The impl that +// exists however is `impl Copy for Foo` and the current rules +// did not consider that a match (something I would like to revise in +// a later PR). + +#![allow(dead_code)] + +use std::kinds::marker; + +#[deriving(Copy)] +struct Foo { x: T } + +type Ty<'tcx> = &'tcx TyS<'tcx>; + +enum TyS<'tcx> { + Boop(marker::InvariantLifetime<'tcx>) +} + +enum Bar<'tcx> { + Baz(Foo>) +} + +impl<'tcx> Copy for Bar<'tcx> { } + +fn main() { } From 3cf0fbeee9b6e90de6e7d44ab9461963729f0365 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Dec 2014 13:37:37 -0500 Subject: [PATCH 10/24] Create distinct types for a PolyTraitRef (with bindings) and a normal TraitRef. --- src/librustc/lint/builtin.rs | 2 +- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 4 +- src/librustc/metadata/tydecode.rs | 10 +- src/librustc/metadata/tyencode.rs | 6 +- src/librustc/middle/astencode.rs | 31 +++- src/librustc/middle/check_static.rs | 18 +-- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/fast_reject.rs | 2 +- src/librustc/middle/infer/coercion.rs | 4 +- src/librustc/middle/infer/combine.rs | 18 ++- src/librustc/middle/infer/equate.rs | 12 +- src/librustc/middle/infer/error_reporting.rs | 6 +- src/librustc/middle/infer/glb.rs | 4 +- .../middle/infer/higher_ranked/mod.rs | 18 +-- src/librustc/middle/infer/lub.rs | 4 +- src/librustc/middle/infer/mod.rs | 24 +-- src/librustc/middle/infer/sub.rs | 4 +- src/librustc/middle/privacy.rs | 10 +- src/librustc/middle/traits/coherence.rs | 8 +- src/librustc/middle/traits/fulfill.rs | 6 +- src/librustc/middle/traits/mod.rs | 12 +- src/librustc/middle/traits/select.rs | 85 +++++----- src/librustc/middle/traits/util.rs | 34 ++-- src/librustc/middle/ty.rs | 152 +++++++++++++----- src/librustc/middle/ty_fold.rs | 16 -- src/librustc/util/ppaux.rs | 39 +++-- src/librustc_trans/save/mod.rs | 4 +- src/librustc_trans/trans/callee.rs | 4 +- src/librustc_trans/trans/common.rs | 4 +- src/librustc_trans/trans/context.rs | 8 +- src/librustc_trans/trans/debuginfo.rs | 10 +- src/librustc_trans/trans/expr.rs | 6 +- src/librustc_trans/trans/meth.rs | 12 +- src/librustc_typeck/astconv.rs | 65 ++++---- src/librustc_typeck/check/_match.rs | 5 + src/librustc_typeck/check/closure.rs | 8 +- src/librustc_typeck/check/method/confirm.rs | 22 +-- src/librustc_typeck/check/method/mod.rs | 10 +- src/librustc_typeck/check/method/probe.rs | 73 ++++----- src/librustc_typeck/check/mod.rs | 104 +++++------- src/librustc_typeck/check/vtable.rs | 43 ++--- src/librustc_typeck/check/wf.rs | 16 +- src/librustc_typeck/coherence/mod.rs | 4 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustc_typeck/collect.rs | 24 +-- src/librustc_typeck/variance.rs | 8 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 12 +- 51 files changed, 516 insertions(+), 469 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 8c25bc702b336..ca8eee847d3f9 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1785,7 +1785,7 @@ impl LintPass for Stability { .. }) => { ty::trait_item(cx.tcx, - trait_ref.def_id, + trait_ref.def_id(), index).def_id() } } diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 4cbb1babf9a2c..1a1c810b27814 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -262,7 +262,7 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId, // if there is one. pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) - -> Option>> { + -> Option>> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_impl_trait(&*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b78112f1f7850..1b3a6c0e6ba39 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -425,11 +425,11 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec { pub fn get_impl_trait<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> Option>> + -> Option>> { let item_doc = lookup_item(id, cdata.data()); reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { - Rc::new(doc_trait_ref(tp, tcx, cdata)) + Rc::new(ty::bind(doc_trait_ref(tp, tcx, cdata))) }) } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index d649c6491314c..3d0b63139e4bc 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -414,7 +414,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { } 'x' => { assert_eq!(next(st), '['); - let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); + let trait_ref = ty::bind(parse_trait_ref(st, |x,y| conv(x,y))); let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, trait_ref, bounds); @@ -669,7 +669,7 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => ty::Predicate::Trait(Rc::new(parse_trait_ref(st, conv))), + 't' => ty::Predicate::Trait(Rc::new(ty::bind(parse_trait_ref(st, conv)))), 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), parse_ty(st, |x,y| conv(x,y))), 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), @@ -759,10 +759,12 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) loop { match next(st) { 'R' => { - param_bounds.region_bounds.push(parse_region(st, |x, y| conv (x, y))); + param_bounds.region_bounds.push( + parse_region(st, |x, y| conv (x, y))); } 'I' => { - param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y)))); + param_bounds.trait_bounds.push( + Rc::new(ty::bind(parse_trait_ref(st, |x,y| conv(x,y))))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 2a057da7db368..fd13ea57e6be0 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -251,7 +251,7 @@ fn enc_sty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { mywrite!(w, "x["); - enc_trait_ref(w, cx, principal); + enc_trait_ref(w, cx, &principal.value); enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } @@ -401,7 +401,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); - enc_trait_ref(w, cx, &**tp); + enc_trait_ref(w, cx, &tp.value); } mywrite!(w, "."); @@ -425,7 +425,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, match *p { ty::Predicate::Trait(ref trait_ref) => { mywrite!(w, "t"); - enc_trait_ref(w, cx, &**trait_ref); + enc_trait_ref(w, cx, &trait_ref.value); } ty::Predicate::Equate(a, b) => { mywrite!(w, "e"); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index a37f9cb939d5e..3f0e28589fc54 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTypeParam", 2, 1, |this| { this.emit_struct("MethodParam", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*p.trait_ref)) + Ok(this.emit_trait_ref(ecx, &p.trait_ref.value)) })); try!(this.emit_struct_field("method_num", 0, |this| { this.emit_uint(p.method_num) @@ -901,7 +901,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTraitObject", 3, 1, |this| { this.emit_struct("MethodObject", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*o.trait_ref)) + Ok(this.emit_trait_ref(ecx, &o.trait_ref.value)) })); try!(this.emit_struct_field("object_trait_id", 0, |this| { Ok(this.emit_def_id(o.object_trait_id)) @@ -1113,7 +1113,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg(0, |this| { try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal)) + Ok(this.emit_trait_ref(ecx, &principal.value)) })); this.emit_struct_field("bounds", 1, |this| { Ok(this.emit_existential_bounds(ecx, b)) @@ -1277,7 +1277,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_trait_ref(ecx, &**trait_ref); + rbml_w.emit_trait_ref(ecx, &trait_ref.value); }) }) } @@ -1356,6 +1356,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Rc>; + fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> Rc>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1455,7 +1457,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::MethodParam { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_trait_ref(dcx)) + Ok(this.read_poly_trait_ref(dcx)) }).unwrap() }, method_num: { @@ -1473,7 +1475,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::MethodObject { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_trait_ref(dcx)) + Ok(this.read_poly_trait_ref(dcx)) }).unwrap() }, object_trait_id: { @@ -1548,6 +1550,19 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap()) } + fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> Rc> { + Rc::new(ty::bind(self.read_opaque(|this, doc| { + let ty = tydecode::parse_trait_ref_data( + doc.data, + dcx.cdata.cnum, + doc.start, + dcx.tcx, + |s, a| this.convert_def_id(dcx, s, a)); + Ok(ty) + }).unwrap())) + } + fn read_type_param_def<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::TypeParameterDef<'tcx> { self.read_opaque(|this, doc| { @@ -1753,7 +1768,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 2 => { let ty_trait = try!(this.read_enum_variant_arg(0, |this| { let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_trait_ref(dcx)) + Ok(this.read_poly_trait_ref(dcx)) })); Ok(ty::TyTrait { principal: (*principal).clone(), @@ -1926,7 +1941,7 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.method_map.borrow_mut().insert(method_call, method); } c::tag_table_object_cast_map => { - let trait_ref = val_dsr.read_trait_ref(dcx); + let trait_ref = val_dsr.read_poly_trait_ref(dcx); dcx.tcx.object_cast_map.borrow_mut() .insert(id, trait_ref); } diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 65412ff8effc9..af2be6e088dd5 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,7 +31,6 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; -use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -122,17 +121,12 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - match traits::trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) { - Ok(trait_ref) => { - fulfill_cx.register_trait_ref(self.tcx, trait_ref, - traits::ObligationCause::dummy()); - let env = ty::empty_parameter_environment(); - if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { - self.tcx.sess.span_err(e.span, "shared static items must have a \ - type which implements Sync"); - } - } - Err(ErrorReported) => { } + fulfill_cx.register_builtin_bound(self.tcx, ty, ty::BoundSync, + traits::ObligationCause::dummy()); + let env = ty::empty_parameter_environment(); + if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { + self.tcx.sess.span_err(e.span, "shared static items must have a \ + type which implements Sync"); } } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 939775e750713..46c4de5c35ed0 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { .. }) => { let trait_item = ty::trait_item(self.tcx, - trait_ref.def_id, + trait_ref.def_id(), index); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 901944cd0168e..41020df63995e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -265,7 +265,7 @@ impl OverloadedCallType { } Some(ref trait_ref) => (*trait_ref).clone(), }; - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) + OverloadedCallType::from_trait_id(tcx, trait_ref.value.def_id) } fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId) @@ -292,7 +292,7 @@ impl OverloadedCallType { } MethodTypeParam(MethodParam { ref trait_ref, .. }) | MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id()) } } } diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 6780177933fd1..2be5e46fcbb68 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -60,7 +60,7 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal.def_id)) + Some(TraitSimplifiedType(trait_info.principal.value.def_id)) } ty::ty_struct(def_id, _) => { Some(StructSimplifiedType(def_id)) diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index edb544aca6d99..805d4532aa1c4 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -354,7 +354,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => { // FIXME what is the purpose of `ty`? - let ty = ty::mk_trait(tcx, (*principal).clone(), bounds); + let ty = ty::mk_trait(tcx, principal.clone(), bounds); Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(), bounds: bounds }, ty_a))) @@ -464,7 +464,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); // FIXME what is purpose of this type `tr`? - let tr = ty::mk_trait(tcx, (*principal).clone(), bounds); + let tr = ty::mk_trait(tcx, principal.clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 1b72a572e9ec0..1681731005db8 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -301,7 +301,21 @@ pub trait Combine<'tcx> { fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>>; + -> cres<'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: substs }) + } + } + + fn poly_trait_refs(&self, + a: &ty::PolyTraitRef<'tcx>, + b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'tcx>>; // this must be overridden to do correctly, so as to account for higher-ranked // behavior } @@ -410,7 +424,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); - let principal = try!(this.trait_refs(&a_.principal, &b_.principal)); + let principal = try!(this.poly_trait_refs(&a_.principal, &b_.principal)); let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); Ok(ty::mk_trait(tcx, principal, bounds)) } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 1738b8db99b37..79fbc33f2a1df 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -134,14 +134,16 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { + -> cres<'tcx, ty::FnSig<'tcx>> + { try!(self.sub().fn_sigs(a, b)); self.sub().fn_sigs(b, a) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { - try!(self.sub().trait_refs(a, b)); - self.sub().trait_refs(b, a) + fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'tcx>> + { + try!(self.sub().poly_trait_refs(a, b)); + self.sub().poly_trait_refs(b, a) } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index e1473847c235b..89d6a7df05098 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1647,13 +1647,13 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { } } -impl<'tcx> Resolvable<'tcx> for Rc> { +impl<'tcx> Resolvable<'tcx> for Rc> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) - -> Rc> { + -> Rc> { Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { - ty::trait_ref_contains_error(&**self) + ty::trait_ref_contains_error(&self.value) } } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 9fc4e095c43bd..f751931a9412e 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -126,8 +126,8 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { self.higher_ranked_glb(a, b) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'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 ef8c2f414acf4..93a4d7c2f46d9 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -377,21 +377,13 @@ impl<'tcx> HigherRankedCombineable<'tcx> for ty::FnSig<'tcx> { } } -impl<'tcx> HigherRankedCombineable<'tcx> for ty::TraitRef<'tcx> { +impl<'tcx> HigherRankedCombineable<'tcx> for ty::PolyTraitRef<'tcx> { fn super_combine>(combiner: &C, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> + a: &ty::PolyTraitRef<'tcx>, + b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'tcx>> { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(ty::terr_traits( - combine::expected_found(combiner, a.def_id, b.def_id))) - } else { - let substs = try!(combiner.substs(a.def_id, &a.substs, &b.substs)); - Ok(ty::TraitRef { def_id: a.def_id, - substs: substs }) - } + Ok(ty::bind(try!(combiner.trait_refs(&a.value, &b.value)))) } } diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index f27b07c9c9d45..e142e3dbe443b 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -122,8 +122,8 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { super_lattice_tys(self, a, b) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'tcx>> { self.higher_ranked_lub(a, b) } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 0c70d2081196d..80508a8f16f1f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -133,7 +133,7 @@ impl Copy for TypeOrigin {} #[deriving(Clone, Show)] pub enum ValuePairs<'tcx> { Types(ty::expected_found>), - TraitRefs(ty::expected_found>>), + TraitRefs(ty::expected_found>>), } /// The trace designates the path through inference that we took to @@ -402,17 +402,17 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, || cx.eq_types(a_is_expected, origin, a, b)) } -pub fn mk_sub_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, +pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, origin: TypeOrigin, - a: Rc>, - b: Rc>) + a: Rc>, + b: Rc>) -> ures<'tcx> { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.commit_if_ok( - || cx.sub_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, @@ -679,12 +679,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - pub fn sub_trait_refs(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: Rc>, - b: Rc>) - -> ures<'tcx> + pub fn sub_poly_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc>, + b: Rc>) + -> ures<'tcx> { debug!("sub_trait_refs({} <: {})", a.repr(self.tcx), @@ -695,7 +695,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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).poly_trait_refs(&*a, &*b).to_ures() }) } } diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 00c79bc726cf6..e7b7791cc2a84 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -160,8 +160,8 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { self.higher_ranked_sub(a, b) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) + -> cres<'tcx, ty::PolyTraitRef<'tcx>> { self.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 8cce1321d728b..b0d62644ca510 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -257,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { }; let tr = ty::impl_trait_ref(self.tcx, local_def(item.id)); let public_trait = tr.clone().map_or(false, |tr| { - !is_local(tr.def_id) || - self.exported_items.contains(&tr.def_id.node) + !is_local(tr.value.def_id) || + self.exported_items.contains(&tr.value.def_id.node) }); if public_ty || public_trait { @@ -407,7 +407,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.def_id) + self.def_privacy(t.value.def_id) } None => { debug!("privacy - found a method {}", @@ -432,7 +432,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.def_id) + self.def_privacy(t.value.def_id) } None => { debug!("privacy - found a typedef {}", @@ -811,7 +811,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // is whether the trait itself is accessible or not. MethodTypeParam(MethodParam { ref trait_ref, .. }) | MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - self.report_error(self.ensure_public(span, trait_ref.def_id, + self.report_error(self.ensure_public(span, trait_ref.def_id(), None, "source trait")); } } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 822979c86017b..011f86e2810ae 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -65,15 +65,15 @@ pub fn impl_is_local(tcx: &ty::ctxt, debug!("trait_ref={}", trait_ref.repr(tcx)); // If the trait is local to the crate, ok. - if trait_ref.def_id.krate == ast::LOCAL_CRATE { + if trait_ref.value.def_id.krate == ast::LOCAL_CRATE { debug!("trait {} is local to current crate", - trait_ref.def_id.repr(tcx)); + trait_ref.value.def_id.repr(tcx)); return true; } // Otherwise, at least one of the input types must be local to the // crate. - trait_ref.input_types().iter().any(|&t| ty_is_local(tcx, t)) + trait_ref.value.input_types().iter().any(|&t| ty_is_local(tcx, t)) } pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -143,7 +143,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_trait(ref tt) => { - tt.principal.def_id.krate == ast::LOCAL_CRATE + tt.principal.value.def_id.krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 412c188f5f4ae..8433313cb3718 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -28,7 +28,7 @@ use super::ObligationCause; use super::PredicateObligation; use super::Selection; use super::select::SelectionContext; -use super::trait_ref_for_builtin_bound; +use super::poly_trait_ref_for_builtin_bound; use super::Unimplemented; /// The fulfillment context is used to drive trait resolution. It @@ -107,7 +107,7 @@ impl<'tcx> FulfillmentContext<'tcx> { builtin_bound: ty::BuiltinBound, cause: ObligationCause<'tcx>) { - match trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { + match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { Ok(trait_ref) => { self.register_trait_ref(tcx, trait_ref, cause); } @@ -117,7 +117,7 @@ impl<'tcx> FulfillmentContext<'tcx> { pub fn register_trait_ref<'a>(&mut self, tcx: &ty::ctxt<'tcx>, - trait_ref: Rc>, + trait_ref: Rc>, cause: ObligationCause<'tcx>) { /*! diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 936304c5eb483..3289acd0c2e5e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -33,7 +33,7 @@ pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; pub use self::util::transitive_bounds; -pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::poly_trait_ref_for_builtin_bound; mod coherence; mod fulfill; @@ -54,7 +54,7 @@ pub struct Obligation<'tcx, T> { } pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; /// Why did we incur this obligation? Used for error reporting. #[deriving(Copy, Clone)] @@ -115,7 +115,9 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc>, Rc>, ty::type_err<'tcx>), + OutputTypeParameterMismatch(Rc>, + Rc>, + ty::type_err<'tcx>), } pub struct FulfillmentError<'tcx> { @@ -226,7 +228,7 @@ pub struct VtableBuiltinData { #[deriving(PartialEq,Eq,Clone)] pub struct VtableParamData<'tcx> { // In the above example, this would `Eq` - pub bound: Rc>, + pub bound: Rc>, } /// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl @@ -278,7 +280,7 @@ impl<'tcx,O> Obligation<'tcx,O> { } } -impl<'tcx> Obligation<'tcx,Rc>> { +impl<'tcx> TraitObligation<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f551ff061654a..86435267be002 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -28,7 +28,7 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, RegionEscape}; use middle::infer; use middle::infer::{InferCtxt, TypeSkolemizer}; use middle::ty_fold::TypeFoldable; @@ -74,14 +74,14 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// Trait ref from `obligation` but skolemized with the /// selection-context's skolemizer. Used to check for recursion. - skol_trait_ref: Rc>, + skol_trait_ref: Rc>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, + hashmap: RefCell>, SelectionResult<'tcx, Candidate<'tcx>>>>, } @@ -347,13 +347,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.skol_trait_ref.input_types(); + let input_types = stack.skol_trait_ref.value.input_types(); let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t)); if unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id)) + |prev| stack.skol_trait_ref.value.def_id == prev.skol_trait_ref.value.def_id)) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", stack.skol_trait_ref.repr(self.tcx())); @@ -569,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn pick_candidate_cache(&self, - cache_skol_trait_ref: &Rc>) + cache_skol_trait_ref: &Rc>) -> &SelectionCache<'tcx> { // High-level idea: we have to decide whether to consult the @@ -591,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_skol_trait_ref.input_types().iter().any( + cache_skol_trait_ref.value.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_skol_trait_ref.input_types().iter().any( + cache_skol_trait_ref.value.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -615,7 +615,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn check_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>) + cache_skol_trait_ref: Rc>) -> Option>> { let cache = self.pick_candidate_cache(&cache_skol_trait_ref); @@ -624,7 +624,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn insert_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>, + cache_skol_trait_ref: Rc>, candidate: SelectionResult<'tcx, Candidate<'tcx>>) { let cache = self.pick_candidate_cache(&cache_skol_trait_ref); @@ -648,7 +648,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.value.def_id) { Some(ty::BoundCopy) => { debug!("obligation self ty is {}", obligation.self_ty().repr(self.tcx())); @@ -696,7 +696,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_caller_bounds({})", obligation.repr(self.tcx())); - let caller_trait_refs: Vec> = + let caller_trait_refs: Vec<_> = self.param_env.caller_bounds.predicates.iter() .filter_map(|o| o.to_trait()) .collect(); @@ -731,7 +731,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) { + let kind = match self.fn_family_trait_kind(obligation.trait_ref.value.def_id) { Some(k) => k, None => { return Ok(()); } }; @@ -779,7 +779,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We provide a `Fn` impl for fn pointers. There is no need to provide // the other traits (e.g. `FnMut`) since those are provided by blanket // impls. - if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() { + if Some(obligation.trait_ref.value.def_id) != self.tcx().lang_items.fn_trait() { return Ok(()); } @@ -814,7 +814,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - let all_impls = self.all_impls(obligation.trait_ref.def_id); + let all_impls = self.all_impls(obligation.trait_ref.value.def_id); for &impl_def_id in all_impls.iter() { self.infcx.probe(|| { match self.match_impl(impl_def_id, obligation) { @@ -926,8 +926,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let origin = infer::RelateOutputImplTypes(stack.obligation.cause.span); self.infcx - .sub_trait_refs(false, origin, - impl_trait_ref, vt.bound.clone()) + .sub_poly_trait_refs(false, origin, impl_trait_ref, vt.bound.clone()) .is_ok() }) } @@ -1071,26 +1070,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + ty::ty_trait(ref data) => { match bound { ty::BoundSized => { Err(Unimplemented) } ty::BoundCopy | ty::BoundSync | ty::BoundSend => { - if bounds.builtin_bounds.contains(&bound) { + if data.bounds.builtin_bounds.contains(&bound) { Ok(If(Vec::new())) } else { // Recursively check all supertraits to find out if any further // bounds are required and thus we must fulfill. - // We have to create a temp trait ref here since TyTraits don't - // have actual self type info (which is required for the - // supertraits iterator). - let tmp_tr = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: principal.substs.with_self_ty(ty::mk_err()) - }); + let tmp_tr = data.principal_trait_ref_with_self_ty(ty::mk_err()); for tr in util::supertraits(self.tcx(), tmp_tr) { - let td = ty::lookup_trait_def(self.tcx(), tr.def_id); + let td = ty::lookup_trait_def(self.tcx(), tr.value.def_id); if td.bounds.builtin_bounds.contains(&bound) { return Ok(If(Vec::new())) @@ -1534,10 +1527,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![], vec![], self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::bind(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); let () = try!(self.confirm(obligation.cause, @@ -1577,10 +1570,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![], vec![], obligation.self_ty()); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::bind(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); debug!("confirm_unboxed_closure_candidate(closure_def_id={}, trait_ref={})", closure_def_id.repr(self.tcx()), @@ -1650,7 +1643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn fast_reject_trait_refs(&mut self, obligation: &TraitObligation, - impl_trait_ref: &ty::TraitRef) + impl_trait_ref: &ty::PolyTraitRef) -> bool { // We can avoid creating type variables and doing the full @@ -1673,7 +1666,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_trait_refs(&mut self, obligation: &TraitObligation<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> Result<(),()> { debug!("match_trait_refs: obligation={} trait_ref={}", @@ -1681,10 +1674,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_ref.repr(self.tcx())); let origin = infer::RelateOutputImplTypes(obligation.cause.span); - match self.infcx.sub_trait_refs(false, - origin, - trait_ref, - obligation.trait_ref.clone()) { + match self.infcx.sub_poly_trait_refs(false, + origin, + trait_ref, + obligation.trait_ref.clone()) { Ok(()) => Ok(()), Err(_) => Err(()), } @@ -1783,7 +1776,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_impl_vtable(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause<'tcx>, - obligation_trait_ref: Rc>, + obligation_trait_ref: Rc>, substs: &Substs<'tcx>) -> Result<(), SelectionError<'tcx>> { @@ -1814,17 +1807,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// we report an error to the user. fn confirm(&mut self, obligation_cause: ObligationCause, - obligation_trait_ref: Rc>, - expected_trait_ref: Rc>) + obligation_trait_ref: Rc>, + expected_trait_ref: Rc>) -> Result<(), SelectionError<'tcx>> { let origin = infer::RelateOutputImplTypes(obligation_cause.span); let obligation_trait_ref = obligation_trait_ref.clone(); - match self.infcx.sub_trait_refs(false, - origin, - expected_trait_ref.clone(), - obligation_trait_ref.clone()) { + match self.infcx.sub_poly_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref.clone()) { Ok(()) => Ok(()), Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index d8956246d326f..2daf5453745b5 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -47,7 +47,7 @@ struct StackEntry<'tcx> { pub fn elaborate_trait_ref<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> Elaborator<'cx, 'tcx> { elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)]) @@ -55,7 +55,7 @@ pub fn elaborate_trait_ref<'cx, 'tcx>( pub fn elaborate_trait_refs<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_refs: &[Rc>]) + trait_refs: &[Rc>]) -> Elaborator<'cx, 'tcx> { let predicates = trait_refs.iter() @@ -174,7 +174,7 @@ pub struct Supertraits<'cx, 'tcx:'cx> { } pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_ref(tcx, trait_ref); @@ -182,15 +182,15 @@ pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, } pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - bounds: &[Rc>]) + bounds: &[Rc>]) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_refs(tcx, bounds); Supertraits { elaborator: elaborator } } -impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option>> { +impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option>> { loop { match self.elaborator.next() { None => { @@ -266,18 +266,18 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, }) } -pub fn trait_ref_for_builtin_bound<'tcx>( +pub fn poly_trait_ref_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, builtin_bound: ty::BuiltinBound, param_ty: Ty<'tcx>) - -> Result>, ErrorReported> + -> Result>, ErrorReported> { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Ok(Rc::new(ty::TraitRef { + Ok(Rc::new(ty::bind(ty::TraitRef { def_id: def_id, substs: Substs::empty().with_self_ty(param_ty) - })) + }))) } Err(e) => { tcx.sess.err(e.as_slice()); @@ -294,7 +294,7 @@ pub fn predicate_for_builtin_bound<'tcx>( param_ty: Ty<'tcx>) -> Result, ErrorReported> { - let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); + let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); Ok(Obligation { cause: cause, recursion_depth: recursion_depth, @@ -306,14 +306,14 @@ pub fn predicate_for_builtin_bound<'tcx>( /// of caller obligations), search through the trait and supertraits to find one where `test(d)` is /// true, where `d` is the def-id of the trait/supertrait. If any is found, return `Some(p)` where /// `p` is the path to that trait/supertrait. Else `None`. -pub fn search_trait_and_supertraits_from_bound<'tcx, F>(tcx: &ty::ctxt<'tcx>, - caller_bound: Rc>, - mut test: F) - -> Option> where - F: FnMut(ast::DefId) -> bool, +pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>, + caller_bound: Rc>, + mut test: F) + -> Option> + where F: FnMut(ast::DefId) -> bool, { for bound in transitive_bounds(tcx, &[caller_bound]) { - if test(bound.def_id) { + if test(bound.def_id()) { let vtable_param = VtableParamData { bound: bound }; return Some(vtable_param); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0ad07bed7d923..ee4097b4d0a9c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -479,7 +479,7 @@ pub enum MethodOrigin<'tcx> { pub struct MethodParam<'tcx> { // the precise trait reference that occurs as a bound -- this may // be a supertrait of what the user actually typed. - pub trait_ref: Rc>, + pub trait_ref: Rc>, // index of uint in the list of methods for the trait pub method_num: uint, @@ -489,7 +489,7 @@ pub struct MethodParam<'tcx> { #[deriving(Clone, Show)] pub struct MethodObject<'tcx> { // the (super)trait containing the method to be invoked - pub trait_ref: Rc>, + pub trait_ref: Rc>, // the actual base trait id of the object pub object_trait_id: ast::DefId, @@ -609,7 +609,7 @@ pub enum vtable_origin<'tcx> { // For every explicit cast into an object type, maps from the cast // expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell>>>; +pub type ObjectCastMap<'tcx> = RefCell>>>; /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. @@ -665,7 +665,7 @@ pub struct ctxt<'tcx> { /// A cache for the trait_items() routine pub trait_items_cache: RefCell>>>>, - pub impl_trait_cache: RefCell>>>>, + pub impl_trait_cache: RefCell>>>>, pub trait_refs: RefCell>>>, pub trait_defs: RefCell>>>, @@ -1308,10 +1308,23 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { // Principal trait reference. - pub principal: TraitRef<'tcx>, // would use Rc, but it runs afoul of some static rules + pub principal: PolyTraitRef<'tcx>, // would use Rc, but it runs afoul of some static rules pub bounds: ExistentialBounds } +impl<'tcx> TyTrait<'tcx> { + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) -> Rc> { + Rc::new(ty::bind(ty::TraitRef { + def_id: self.principal.value.def_id, + substs: self.principal.value.substs.with_self_ty(self_ty), + })) + } +} + /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where clause: /// @@ -1333,6 +1346,26 @@ pub struct TraitRef<'tcx> { pub substs: Substs<'tcx>, } +pub type PolyTraitRef<'tcx> = Binder>; + +impl<'tcx> PolyTraitRef<'tcx> { + pub fn self_ty(&self) -> Ty<'tcx> { + self.value.self_ty() + } + + pub fn def_id(&self) -> ast::DefId { + self.value.def_id + } + + pub fn substs(&self) -> &Substs<'tcx> { + &self.value.substs + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.value.input_types() + } +} + /// Binder serves as a synthetic binder for lifetimes. It is used when /// we wish to replace the escaping higher-ranked lifetimes in a type /// or something else that is not itself a binder (this is because the @@ -1416,7 +1449,7 @@ impl<'tcx> Copy for type_err<'tcx> {} pub struct ParamBounds<'tcx> { pub region_bounds: Vec, pub builtin_bounds: BuiltinBounds, - pub trait_bounds: Vec>> + pub trait_bounds: Vec>> } /// Bounds suitable for an existentially quantified type parameter @@ -1657,7 +1690,7 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the parameters in the `TypeSpace`. - Trait(Rc>), + Trait(Rc>), /// where `T1 == T2`. Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>), @@ -1680,7 +1713,7 @@ impl<'tcx> Predicate<'tcx> { } } - pub fn to_trait(&self) -> Option>> { + pub fn to_trait(&self) -> Option>> { match *self { Predicate::Trait(ref t) => { Some(t.clone()) @@ -1748,14 +1781,6 @@ impl<'tcx> TraitRef<'tcx> { // associated types. self.substs.types.as_slice() } - - pub fn has_escaping_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(1) - } - - pub fn has_bound_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(0) - } } /// When type checking, we use the `ParameterEnvironment` to track @@ -2160,7 +2185,7 @@ impl FlagComputation { &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); - computation.add_substs(&principal.substs); + computation.add_substs(principal.substs()); self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2366,7 +2391,7 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, - principal: ty::TraitRef<'tcx>, + principal: ty::PolyTraitRef<'tcx>, bounds: ExistentialBounds) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2439,7 +2464,7 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { maybe_walk_ty(tm.ty, f); } ty_trait(box TyTrait { ref principal, .. }) => { - for subty in principal.substs.types.iter() { + for subty in principal.substs().types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -3182,7 +3207,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { fn kind_bounds_to_contents<'tcx>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc>]) + traits: &[Rc>]) -> TypeContents { let _i = indenter(); let mut tc = TC::All; @@ -3198,7 +3223,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { // those inherited from traits with builtin-kind-supertraits. fn each_inherited_builtin_bound<'tcx, F>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc>], + traits: &[Rc>], mut f: F) where F: FnMut(BuiltinBound), { @@ -3207,7 +3232,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } each_bound_trait_and_supertraits(cx, traits, |trait_ref| { - let trait_def = lookup_trait_def(cx, trait_ref.def_id); + let trait_def = lookup_trait_def(cx, trait_ref.def_id()); for bound in trait_def.bounds.builtin_bounds.iter() { f(bound); } @@ -4393,7 +4418,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_bare_fn(_) => "extern fn".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal.def_id)) + format!("trait {}", item_path_str(cx, inner.principal.def_id())) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4760,7 +4785,7 @@ pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) } pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Option>> { + -> Option>> { memoized(&cx.impl_trait_cache, id, |id: ast::DefId| { if id.krate == ast::LOCAL_CRATE { debug!("(impl_trait_ref) searching for trait impl {}", id); @@ -4770,7 +4795,9 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) ast::ItemImpl(_, _, ref opt_trait, _, _) => { match opt_trait { &Some(ref t) => { - Some(ty::node_id_to_trait_ref(cx, t.ref_id)) + let trait_ref = + (*ty::node_id_to_trait_ref(cx, t.ref_id)).clone(); + Some(Rc::new(ty::bind(trait_ref))) } &None => None } @@ -4813,7 +4840,7 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: Ty) -> Option { match ty.sty { ty_trait(ref tt) => - Some(tt.principal.def_id), + Some(tt.principal.def_id()), ty_struct(id, _) | ty_enum(id, _) | ty_unboxed_closure(id, _, _) => @@ -5073,10 +5100,10 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) /// Given a reference to a trait, returns the "superbounds" declared /// on the trait, with appropriate substitutions applied. pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, - trait_ref: &TraitRef<'tcx>) + trait_ref: &PolyTraitRef<'tcx>) -> Vec> { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = lookup_trait_def(tcx, trait_ref.def_id()); debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})", trait_def.repr(tcx), trait_ref.repr(tcx)); @@ -5149,8 +5176,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_def.bounds.trait_bounds .iter() .map(|bound_trait_ref| { - ty::TraitRef::new(bound_trait_ref.def_id, - bound_trait_ref.substs.subst(tcx, &trait_ref.substs)) + ty::bind( + ty::TraitRef::new(bound_trait_ref.def_id(), + bound_trait_ref.substs().subst(tcx, trait_ref.substs()))) }) .map(|bound_trait_ref| Rc::new(bound_trait_ref)) .collect(); @@ -5161,9 +5189,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, // The region bounds and builtin bounds do not currently introduce // binders so we can just substitute in a straightforward way here. let region_bounds = - trait_def.bounds.region_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.region_bounds.subst(tcx, trait_ref.substs()); let builtin_bounds = - trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.builtin_bounds.subst(tcx, trait_ref.substs()); let bounds = ty::ParamBounds { trait_bounds: trait_bounds, @@ -5183,7 +5211,7 @@ pub fn predicates<'tcx>( let mut vec = Vec::new(); for builtin_bound in bounds.builtin_bounds.iter() { - match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); } Err(ErrorReported) => { } } @@ -5545,10 +5573,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[Rc>], + bounds: &[Rc>], mut f: F) -> bool where - F: FnMut(Rc>) -> bool, + F: FnMut(Rc>) -> bool, { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { if !f(bound_trait_ref) { @@ -5559,7 +5587,7 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, } pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - opt_principal: Option<&TraitRef<'tcx>>, // None for boxed closures + opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures others: BuiltinBounds) -> Vec { @@ -5569,8 +5597,8 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, let open_ty = ty::mk_infer(tcx, SkolemizedTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { - let substs = principal.substs.with_self_ty(open_ty); - vec!(Rc::new(ty::TraitRef::new(principal.def_id, substs))) + let substs = principal.substs().with_self_ty(open_ty); + vec!(Rc::new(ty::bind(ty::TraitRef::new(principal.def_id(), substs)))) }); let param_bounds = ty::ParamBounds { @@ -5663,7 +5691,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, // Record the trait->implementation mappings, if applicable. let associated_traits = csearch::get_impl_trait(tcx, impl_def_id); for trait_ref in associated_traits.iter() { - record_trait_implementation(tcx, trait_ref.def_id, impl_def_id); + record_trait_implementation(tcx, trait_ref.def_id(), impl_def_id); } // For any methods that use a default implementation, add them to @@ -5938,11 +5966,11 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { } ty_trait(box TyTrait { ref principal, bounds }) => { byte!(17); - did(state, principal.def_id); + did(state, principal.def_id()); hash!(bounds); let principal = anonymize_late_bound_regions(tcx, principal); - for subty in principal.substs.types.iter() { + for subty in principal.substs().types.iter() { helper(tcx, *subty, svh, state); } @@ -6200,7 +6228,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, accumulator.push(region) } ty_trait(ref t) => { - accumulator.push_all(t.principal.substs.regions().as_slice()); + accumulator.push_all(t.principal.substs().regions().as_slice()); } ty_enum(_, ref substs) | ty_struct(_, ref substs) => { @@ -6538,3 +6566,43 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, Ok(()) } + +pub trait RegionEscape { + fn has_escaping_regions(&self) -> bool { + self.has_regions_escaping_depth(0) + } + + fn has_regions_escaping_depth(&self, depth: uint) -> bool; +} + +impl<'tcx> RegionEscape for Ty<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + ty::type_escapes_depth(*self, depth) + } +} + +impl RegionEscape for Region { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.escapes_depth(depth) + } +} + +impl<'tcx> RegionEscape for TraitRef<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) && + self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth)) + } +} + +impl<'tcx,T:RegionEscape> RegionEscape for Binder { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.value.has_regions_escaping_depth(depth + 1) + } +} + +impl Binder { + pub fn has_bound_regions(&self) -> bool { + self.value.has_regions_escaping_depth(0) + } +} + diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 3da9fba0ee89d..da6ddf7461b35 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -583,16 +583,6 @@ pub fn super_fold_closure_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, pub fn super_fold_trait_ref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> -{ - this.enter_region_binder(); - let result = super_fold_trait_ref_contents(this, t); - this.exit_region_binder(); - result -} - -pub fn super_fold_trait_ref_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - t: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { ty::TraitRef { def_id: t.def_id, @@ -722,12 +712,6 @@ impl<'tcx> HigherRankedFoldable<'tcx> for ty::FnSig<'tcx> { } } -impl<'tcx> HigherRankedFoldable<'tcx> for ty::TraitRef<'tcx> { - fn fold_contents>(&self, folder: &mut F) -> ty::TraitRef<'tcx> { - super_fold_trait_ref_contents(folder, self) - } -} - impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> HigherRankedFoldable<'tcx> for ty::Binder { fn fold_contents>(&self, folder: &mut F) -> ty::Binder { ty::bind(self.value.fold_with(folder)) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 13b5c262bf782..afa7ce1867554 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -433,16 +433,11 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - let base = ty::item_path_str(cx, principal.def_id); - let trait_def = ty::lookup_trait_def(cx, principal.def_id); - let did = trait_def.trait_ref.def_id; - let ty = parameterized(cx, base.as_slice(), - &principal.substs, &trait_def.generics, - did); + let principal = principal.user_string(cx); let bound_str = bounds.user_string(cx); let bound_sep = if bound_str.is_empty() { "" } else { " + " }; format!("{}{}{}", - ty, + principal, bound_sep, bound_str) } @@ -749,7 +744,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { // tells you everything you need to know. let base = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("<{} : {}>", + format!("TraitRef({}, {})", self.substs.self_ty().repr(tcx), parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics, self.def_id)) } @@ -1161,7 +1156,7 @@ impl<'tcx> UserString<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { +impl<'tcx> UserString<'tcx> for ty::PolyTraitRef<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String { // Replace any anonymous late-bound regions with named // variants, using gensym'd identifiers, so that we can @@ -1178,7 +1173,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => { - let name = token::gensym("r"); + let name = token::gensym("'r"); names.push(token::get_name(name)); ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name) } @@ -1186,19 +1181,21 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { }); let names: Vec<_> = names.iter().map(|s| s.get()).collect(); - // Let the base string be either `SomeTrait` for `for<'a,'b> SomeTrait`, - // depending on whether there are bound regions. - let path_str = ty::item_path_str(tcx, self.def_id); - let base = - if names.is_empty() { - path_str - } else { - format!("for<{}> {}", names.connect(","), path_str) - }; + let trait_ref_str = trait_ref.value.user_string(tcx); + if names.len() == 0 { + trait_ref_str + } else { + format!("for<{}> {}", names.connect(","), trait_ref_str) + } + } +} +impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + let path_str = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - let did = trait_def.trait_ref.def_id; - parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics, did) + parameterized(tcx, path_str.as_slice(), &self.substs, + &trait_def.generics, self.def_id) } } diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 1a4f06663ef3b..2162055f28782 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -941,14 +941,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ty::MethodTypeParam(ref mp) => { // method invoked on a type parameter let trait_item = ty::trait_item(&self.analysis.ty_cx, - mp.trait_ref.def_id, + mp.trait_ref.def_id(), mp.method_num); (None, Some(trait_item.def_id())) } ty::MethodTraitObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, - mo.trait_ref.def_id, + mo.trait_ref.def_id(), mo.method_num); (None, Some(trait_item.def_id())) } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index ff2f686fff876..7c2f719611632 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -426,7 +426,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( // Compute the first substitution let first_subst = - ty::make_substs_for_receiver_types(tcx, &*trait_ref, &*method) + ty::make_substs_for_receiver_types(tcx, &trait_ref.value, &*method) .erase_regions(); // And compose them @@ -435,7 +435,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( debug!("trans_fn_with_vtables - default method: \ substs = {}, trait_subst = {}, \ first_subst = {}, new_subst = {}", - substs.repr(tcx), trait_ref.substs.repr(tcx), + substs.repr(tcx), trait_ref.substs().repr(tcx), first_subst.repr(tcx), new_substs.repr(tcx)); (true, source_id, new_substs) diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 83938fa335708..ab18a05a2511f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -764,7 +764,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ex: &ast::Expr) -> T /// guarantee to us that all nested obligations *could be* resolved if we wanted to. pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, span: Span, - trait_ref: Rc>) + trait_ref: Rc>) -> traits::Vtable<'tcx, ()> { let tcx = ccx.tcx(); @@ -783,7 +783,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans fulfill_obligation: trait_ref={}", trait_ref.repr(ccx.tcx())); - ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id); + ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id()); let infcx = infer::new_infer_ctxt(tcx); // Parameter environment is used to give details about type parameters, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 89fa6a72e883d..af003b011579f 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -99,7 +99,7 @@ pub struct LocalCrateContext<'tcx> { monomorphized: RefCell, ValueRef>>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell, Rc>), ValueRef>>, + vtables: RefCell, Rc>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -150,7 +150,7 @@ pub struct LocalCrateContext<'tcx> { /// contexts around the same size. n_llvm_insns: Cell, - trait_cache: RefCell>, + trait_cache: RefCell>, traits::Vtable<'tcx, ()>>>, } @@ -601,7 +601,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell, Rc>), + pub fn vtables<'a>(&'a self) -> &'a RefCell, Rc>), ValueRef>> { &self.local.vtables } @@ -699,7 +699,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } - pub fn trait_cache(&self) -> &RefCell>, + pub fn trait_cache(&self) -> &RefCell>, traits::Vtable<'tcx, ()>>> { &self.local.trait_cache } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index e9730f7af0ec1..8fcab0a3144d1 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -429,8 +429,8 @@ impl<'tcx> TypeMap<'tcx> { from_def_id_and_substs(self, cx, - trait_data.principal.def_id, - &trait_data.principal.substs, + trait_data.principal.def_id(), + trait_data.principal.substs(), &mut unique_type_id); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { @@ -2834,7 +2834,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let def_id = match trait_type.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id, + ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id(), _ => { let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ @@ -3765,8 +3765,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(']'); }, ty::ty_trait(ref trait_data) => { - push_item_name(cx, trait_data.principal.def_id, false, output); - push_type_params(cx, &trait_data.principal.substs, output); + push_item_name(cx, trait_data.principal.def_id(), false, output); + push_type_params(cx, trait_data.principal.substs(), output); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == ast::Unsafety::Unsafe { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 304142453a9c8..0bcca6c80ff0d 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -316,10 +316,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.ty_to_string(unadjusted_ty)).as_slice()) }, &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { - let substs = principal.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions(); let trait_ref = - Rc::new(ty::TraitRef { def_id: principal.def_id, - substs: substs }); + Rc::new(ty::bind(ty::TraitRef { def_id: principal.def_id(), + substs: substs })); let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); let box_ty = mk_ty(unadjusted_ty); PointerCast(bcx, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 9a2bc38acdfdc..b386df85d627e 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -142,7 +142,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, span, (*trait_ref).clone()); debug!("origin = {}", origin.repr(bcx.tcx())); - trans_monomorphized_callee(bcx, method_call, trait_ref.def_id, + trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(), method_num, origin) } @@ -239,8 +239,8 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_assoc, Vec::new())); debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); - let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id, - substs: trait_substs }); + let trait_ref = Rc::new(ty::bind(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); let vtbl = fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref); @@ -515,7 +515,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// This will hopefully change now that DST is underway. pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, box_ty: Ty<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> ValueRef { debug!("get_vtable(box_ty={}, trait_ref={})", @@ -618,7 +618,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let trt_id = match ty::impl_trait_ref(tcx, impl_id) { - Some(t_id) => t_id.def_id, + Some(t_id) => t_id.def_id(), None => ccx.sess().bug("make_impl_vtable: don't know how to \ make a vtable for a type impl!") }; @@ -670,7 +670,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Expr>, id: ast::NodeId, - trait_ref: Rc>, + trait_ref: Rc>, dest: expr::Dest) -> Block<'blk, 'tcx> { let mut bcx = bcx; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 87eda76db2990..1acd5684d169c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -524,6 +524,19 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } +pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + ast_trait_ref: &ast::PolyTraitRef, + self_ty: Option>, + allow_eq: AllowEqConstraints) + -> Rc> + where AC: AstConv<'tcx>, RS: RegionScope +{ + let trait_ref = instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); + let trait_ref = (*trait_ref).clone(); + Rc::new(ty::bind(trait_ref)) // Ugh. +} /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. @@ -537,9 +550,7 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, where AC: AstConv<'tcx>, RS: RegionScope { - match ::lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, @@ -749,7 +760,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ty: &ast::Ty, bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> + -> Result, ErrorReported> where AC : AstConv<'tcx>, RS : RegionScope { /*! @@ -767,12 +778,12 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - return Ok(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow)); + return Ok(ty::bind(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow))); } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -814,7 +825,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope: &RS, span: Span, - trait_ref: ty::TraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, bounds: &[ast::TyParamBound]) -> Ty<'tcx> where AC : AstConv<'tcx>, RS : RegionScope @@ -982,12 +993,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let result = ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow); + let result = ty::bind(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow)); trait_ref_to_object_type(this, rscope, path.span, result, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { @@ -1039,7 +1050,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let ty_param_defs = tcx.ty_param_defs.borrow(); let tp_def = &(*ty_param_defs)[did.node]; let assoc_tys = tp_def.bounds.trait_bounds.iter() - .filter_map(|b| find_assoc_ty(this, &**b, assoc_ident)) + .filter_map(|b| find_assoc_ty(this, &b.value, assoc_ident)) .collect(); (assoc_tys, token::get_name(tp_def.name).to_string()) } @@ -1423,7 +1434,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds { @@ -1450,11 +1461,11 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_trait_ref(this, - rscope, - &trait_bound.trait_ref, - None, - AllowEqConstraints::Allow)) + Some(instantiate_poly_trait_ref(this, + rscope, + trait_bound, + None, + AllowEqConstraints::Allow)) } None => { this.tcx().sess.span_err( @@ -1481,7 +1492,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds where AC: AstConv<'tcx>, RS:RegionScope @@ -1519,7 +1530,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, explicit_region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, builtin_bounds: ty::BuiltinBounds) -> Option { @@ -1579,7 +1590,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( rscope: &RS, span: Span, region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures builtin_bounds: ty::BuiltinBounds) -> ty::Region { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b31683219f1cd..44cc5fce53da3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -18,6 +18,7 @@ use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; use check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; use require_same_types; use util::nodemap::FnvHashMap; +use util::ppaux::Repr; use std::cmp; use std::collections::hash_map::{Occupied, Vacant}; @@ -33,6 +34,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; + debug!("check_pat(pat={},expected={})", + pat.repr(tcx), + expected.repr(tcx)); + match pat.node { ast::PatWild(_) => { fcx.write_ty(pat.id, expected); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index a4fee8573c592..6e5fdbfac9fd3 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -180,7 +180,7 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>( fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( fcx: &FnCtxt<'a,'tcx>, - trait_ref: &ty::TraitRef<'tcx>) + trait_ref: &ty::PolyTraitRef<'tcx>) -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)> { let tcx = fcx.tcx(); @@ -188,14 +188,14 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("deduce_unboxed_closure_expectations_from_object_type({})", trait_ref.repr(tcx)); - let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id) { + let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) { Some(k) => k, None => { return None; } }; debug!("found object type {}", kind); - let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0); + let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); @@ -205,7 +205,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( }; debug!("input_tys {}", input_tys.repr(tcx)); - let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1); + let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1); let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7463652a93136..0d07957ba3d97 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -222,15 +222,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // argument type), but those cases have already // been ruled out when we deemed the trait to be // "object safe". - let substs = data.principal.substs.clone().with_self_ty(object_ty); let original_trait_ref = - Rc::new(ty::TraitRef::new(data.principal.def_id, substs)); - let upcast_trait_ref = this.upcast(original_trait_ref.clone(), trait_def_id); + data.principal_trait_ref_with_self_ty(object_ty); + let upcast_trait_ref = + this.upcast(original_trait_ref.clone(), trait_def_id); debug!("original_trait_ref={} upcast_trait_ref={} target_trait={}", original_trait_ref.repr(this.tcx()), upcast_trait_ref.repr(this.tcx()), trait_def_id.repr(this.tcx())); - let substs = upcast_trait_ref.substs.clone(); + let substs = upcast_trait_ref.substs().clone(); let origin = MethodTraitObject(MethodObject { trait_ref: upcast_trait_ref, object_trait_id: trait_def_id, @@ -257,7 +257,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .subst(self.tcx(), &impl_polytype.substs); let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(), method_num: method_num }); - (impl_trait_ref.substs.clone(), origin) + (impl_trait_ref.substs().clone(), origin) } probe::TraitPick(trait_def_id, method_num) => { @@ -272,16 +272,16 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { &trait_def.generics, self.infcx().next_ty_var()); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); + let trait_ref = Rc::new(ty::bind(ty::TraitRef::new(trait_def_id, substs.clone()))); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) } probe::WhereClausePick(ref trait_ref, method_num) => { - let origin = MethodTypeParam(MethodParam { trait_ref: (*trait_ref).clone(), + let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref.clone(), method_num: method_num }); - (trait_ref.substs.clone(), origin) + (trait_ref.substs().clone(), origin) } } } @@ -637,12 +637,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn upcast(&mut self, - source_trait_ref: Rc>, + source_trait_ref: Rc>, target_trait_def_id: ast::DefId) - -> Rc> + -> Rc> { for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { - if super_trait_ref.def_id == target_trait_def_id { + if super_trait_ref.def_id() == target_trait_def_id { return super_trait_ref; } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ac7bc81b2f874..14bd0edda1078 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -166,7 +166,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Construct a trait-reference `self_ty : Trait` let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); + let trait_ref = Rc::new(ty::bind(ty::TraitRef::new(trait_def_id, substs))); // Construct an obligation let obligation = traits::Obligation::misc(span, @@ -198,7 +198,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Note that as the method comes from a trait, it can only have // late-bound regions from the fn itself, not the impl. let ref bare_fn_ty = method_ty.fty; - let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs); + let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs()); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; @@ -221,7 +221,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), &trait_ref.substs); + let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs()); assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( traits::ObligationCause::misc(span, fcx.body_id), @@ -293,7 +293,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(), method_num: method_num}), ty: fty, - substs: trait_ref.substs.clone() + substs: trait_ref.substs().clone() }; debug!("callee = {}", callee.repr(fcx.tcx())); @@ -379,7 +379,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None => format!(""), Some(trait_ref) => format!(" of the trait `{}`", ty::item_path_str(fcx.tcx(), - trait_ref.def_id)), + trait_ref.def_id())), }; span_note!(fcx.sess(), method_span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 80e511b8fdf6f..452d001fe8aa9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -59,10 +59,10 @@ struct Candidate<'tcx> { enum CandidateKind<'tcx> { InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), ObjectCandidate(MethodObject<'tcx>), - ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, + ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), - WhereClauseCandidate(Rc>, MethodIndex), + WhereClauseCandidate(Rc>, MethodIndex), } pub struct Pick<'tcx> { @@ -77,7 +77,7 @@ pub enum PickKind<'tcx> { ObjectPick(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex), TraitPick(/* Trait */ ast::DefId, MethodIndex), - WhereClausePick(/* Trait */ Rc>, MethodIndex), + WhereClausePick(/* Trait */ Rc>, MethodIndex), } pub type PickResult<'tcx> = Result, MethodError>; @@ -231,9 +231,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx())); match self_ty.sty { - ty::ty_trait(box ty::TyTrait { ref principal, bounds, .. }) => { - self.assemble_inherent_candidates_from_object(self_ty, &*principal, bounds); - self.assemble_inherent_impl_candidates_for_type(principal.def_id); + ty::ty_trait(box ref data) => { + self.assemble_inherent_candidates_from_object(self_ty, data); + self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::ty_enum(did, _) | ty::ty_struct(did, _) | @@ -290,8 +290,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>, - principal: &ty::TraitRef<'tcx>, - _bounds: ty::ExistentialBounds) { + data: &ty::TyTrait<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={})", self_ty.repr(self.tcx())); @@ -304,26 +303,20 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // a substitution that replaces `Self` with the object type // itself. Hence, a `&self` method will wind up with an // argument type like `&Trait`. - let rcvr_substs = principal.substs.clone().with_self_ty(self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: rcvr_substs.clone() - }); - + let trait_ref = data.principal_trait_ref_with_self_ty(self_ty); self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| { let vtable_index = - get_method_index(tcx, &*new_trait_ref, - trait_ref.clone(), method_num); + get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); let xform_self_ty = - this.xform_self_ty(&m, &new_trait_ref.substs); + this.xform_self_ty(&m, new_trait_ref.substs()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, method_ty: m, kind: ObjectCandidate(MethodObject { trait_ref: new_trait_ref, - object_trait_id: principal.def_id, + object_trait_id: trait_ref.def_id(), method_num: method_num, real_index: vtable_index }) @@ -358,27 +351,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| { let xform_self_ty = - this.xform_self_ty(&m, &trait_ref.substs); + this.xform_self_ty(&m, trait_ref.substs()); debug!("found match: trait_ref={} substs={} m={}", trait_ref.repr(this.tcx()), - trait_ref.substs.repr(this.tcx()), + trait_ref.substs().repr(this.tcx()), m.repr(this.tcx())); assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(), - trait_ref.substs.types.get_slice(subst::TypeSpace).len()); + trait_ref.substs().types.get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(), - trait_ref.substs.regions().get_slice(subst::TypeSpace).len()); + trait_ref.substs().regions().get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(), - trait_ref.substs.types.get_slice(subst::SelfSpace).len()); + trait_ref.substs().types.get_slice(subst::SelfSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), - trait_ref.substs.regions().get_slice(subst::SelfSpace).len()); + trait_ref.substs().regions().get_slice(subst::SelfSpace).len()); // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the // `WhereClauseCandidate` and (eventually) into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -392,10 +385,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // create the candidates. fn elaborate_bounds( &mut self, - bounds: &[Rc>], + bounds: &[Rc>], num_includes_types: bool, mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: Rc>, + tr: Rc>, m: Rc>, method_num: uint|) { @@ -405,12 +398,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let mut cache = HashSet::new(); for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { // Already visited this trait, skip it. - if !cache.insert(bound_trait_ref.def_id) { + if !cache.insert(bound_trait_ref.def_id()) { continue; } let (pos, method) = match trait_method(tcx, - bound_trait_ref.def_id, + bound_trait_ref.def_id(), self.method_name, num_includes_types) { Some(v) => v, @@ -418,7 +411,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }; if !self.has_applicable_self(&*method) { - self.record_static_candidate(TraitSource(bound_trait_ref.def_id)); + self.record_static_candidate(TraitSource(bound_trait_ref.def_id())); } else { mk_cand(self, bound_trait_ref, method, pos); } @@ -510,7 +503,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Determine the receiver type that the method itself expects. let xform_self_ty = - self.xform_self_ty(&method, &impl_trait_ref.substs); + self.xform_self_ty(&method, impl_trait_ref.substs()); debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx())); @@ -1007,8 +1000,8 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Determine the index of a method in the list of all methods belonging // to a trait and its supertraits. fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - subtrait: Rc>, + trait_ref: &ty::PolyTraitRef<'tcx>, + subtrait: Rc>, n_method: uint) -> uint { // We need to figure the "real index" of the method in a // listing of all the methods of an object. We do this by @@ -1017,10 +1010,10 @@ fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, // methods from them. let mut method_count = n_method; ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| { - if bound_ref.def_id == trait_ref.def_id { + if bound_ref.def_id() == trait_ref.def_id() { false } else { - let trait_items = ty::trait_items(tcx, bound_ref.def_id); + let trait_items = ty::trait_items(tcx, bound_ref.def_id()); for trait_item in trait_items.iter() { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, @@ -1043,7 +1036,7 @@ impl<'tcx> Candidate<'tcx> { InherentImplPick(def_id) } ObjectCandidate(ref data) => { - ObjectPick(data.trait_ref.def_id, data.method_num, data.real_index) + ObjectPick(data.trait_ref.def_id(), data.method_num, data.real_index) } ExtensionImplCandidate(def_id, _, _, index) => { ExtensionImplPick(def_id, index) @@ -1057,7 +1050,7 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); WhereClausePick((*trait_ref).clone(), index) } @@ -1068,10 +1061,10 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { InherentImplCandidate(def_id, _) => ImplSource(def_id), - ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id), + ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id()), ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), - WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id), + WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), } } @@ -1086,7 +1079,7 @@ impl<'tcx> Candidate<'tcx> { } ExtensionImplCandidate(_, ref trait_ref, _, method_num) | WhereClauseCandidate(ref trait_ref, method_num) => { - Some((trait_ref.def_id, method_num)) + Some((trait_ref.def_id(), method_num)) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eabf52c2cc8b3..1e9f7992fb742 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -625,23 +625,20 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env); } - ast::ItemImpl(_, _, ref opt_trait_ref, _, ref impl_items) => { + ast::ItemImpl(_, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - match *opt_trait_ref { - Some(ref ast_trait_ref) => { - let impl_trait_ref = - ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id); + match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) { + Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, it.span, - ast_trait_ref, &*impl_trait_ref, impl_items.as_slice()); - } - None => { } - } + } + None => { } + } for impl_item in impl_items.iter() { match *impl_item { @@ -739,12 +736,11 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, - ast_trait_ref: &ast::TraitRef, - impl_trait_ref: &ty::TraitRef<'tcx>, + impl_trait_ref: &ty::PolyTraitRef<'tcx>, impl_items: &[ast::ImplItem]) { // Locate trait methods let tcx = ccx.tcx; - let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id); + let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id()); // Check existing impl methods to see if they are both present in trait // and compatible with trait signature @@ -772,21 +768,16 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_method.span, impl_method.pe_body().id, &**trait_method_ty, - impl_trait_ref); + &*impl_trait_ref); } _ => { // This is span_bug as it should have already been // caught in resolve. - tcx.sess - .span_bug(impl_method.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + impl_method.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -795,11 +786,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // caught in resolve. tcx.sess.span_bug( impl_method.span, - format!( - "method `{}` is not a member of trait `{}`", - token::get_name(impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + format!("method `{}` is not a member of trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -812,27 +801,19 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // corresponding type definition in the trait. let opt_associated_type = trait_items.iter() - .find(|ti| { - ti.name() == typedef_ty.name() - }); + .find(|ti| ti.name() == typedef_ty.name()); match opt_associated_type { Some(associated_type) => { match (associated_type, &typedef_ty) { - (&ty::TypeTraitItem(_), - &ty::TypeTraitItem(_)) => {} + (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {} _ => { // This is `span_bug` as it should have // already been caught in resolve. - tcx.sess - .span_bug(typedef.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + typedef.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(typedef_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -845,8 +826,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, "associated type `{}` is not a member of \ trait `{}`", token::get_name(typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -855,7 +835,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Check for missing items from trait let provided_methods = ty::provided_trait_methods(tcx, - impl_trait_ref.def_id); + impl_trait_ref.def_id()); let mut missing_methods = Vec::new(); for trait_item in trait_items.iter() { match *trait_item { @@ -870,8 +850,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }); let is_provided = - provided_methods.iter().any( - |m| m.name == trait_method.name); + provided_methods.iter().any(|m| m.name == trait_method.name); if !is_implemented && !is_provided { missing_methods.push(format!("`{}`", token::get_name(trait_method.name))); } @@ -915,7 +894,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + impl_trait_ref: &ty::PolyTraitRef<'tcx>) { debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); @@ -945,7 +924,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let infcx = infer::new_infer_ctxt(tcx); - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs(); // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected @@ -1167,20 +1146,20 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); let infcx = infer::new_infer_ctxt(tcx); - infer::mk_sub_trait_refs(&infcx, - true, - infer::Misc(impl_m_span), - trait_bound, - impl_trait_bound.clone()).is_ok() + infer::mk_sub_poly_trait_refs(&infcx, + true, + infer::Misc(impl_m_span), + trait_bound, + impl_trait_bound.clone()).is_ok() }); if !found_match_in_trait { span_err!(tcx.sess, impl_m_span, E0052, - "in method `{}`, type parameter {} requires bound `{}`, which is not \ - required by the corresponding type parameter in the trait declaration", - token::get_name(trait_m.name), - i, - ppaux::trait_ref_to_string(tcx, &*impl_trait_bound)); + "in method `{}`, type parameter {} requires bound `{}`, which is not \ + required by the corresponding type parameter in the trait declaration", + token::get_name(trait_m.name), + i, + impl_trait_bound.user_string(tcx)); } } } @@ -1647,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_object_cast(&self, key: ast::NodeId, - trait_ref: Rc>) { + trait_ref: Rc>) { debug!("write_object_cast key={} trait_ref={}", key, trait_ref.repr(self.tcx())); self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); @@ -1745,7 +1724,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), &ty_trait.principal, span); + vtable::check_object_safety(self.tcx(), ty_trait, span); + // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: vtable::register_object_cast_obligations(self, diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 664705c89ab2a..4a10c698f7d1f 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -9,7 +9,7 @@ // except according to those terms. use check::{FnCtxt, structurally_resolved_type}; -use middle::subst::{SelfSpace, FnSpace}; +use middle::subst::{FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; use middle::traits::{Obligation, ObligationCause}; @@ -44,7 +44,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Ensure that if ~T is cast to ~Trait, then T : Trait push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, @@ -68,7 +68,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, target_region, referent_region); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } } @@ -132,24 +132,19 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // self by value, has no type parameters and does not use the `Self` type, except // in self position. pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, - span: Span) { - - let mut object = object_trait.clone(); - if object.substs.types.len(SelfSpace) == 0 { - object.substs.types.push(SelfSpace, ty::mk_err()); - } - - let object = Rc::new(object); - for tr in traits::supertraits(tcx, object) { + object_trait: &ty::TyTrait<'tcx>, + span: Span) +{ + let object_trait_ref = object_trait.principal_trait_ref_with_self_ty(ty::mk_err()); + for tr in traits::supertraits(tcx, object_trait_ref) { check_object_safety_inner(tcx, &*tr, span); } } fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, + object_trait: &ty::PolyTraitRef<'tcx>, span: Span) { - let trait_items = ty::trait_items(tcx, object_trait.def_id); + let trait_items = ty::trait_items(tcx, object_trait.def_id()); let mut errors = Vec::new(); for item in trait_items.iter() { @@ -163,7 +158,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, let mut errors = errors.iter().flat_map(|x| x.iter()).peekable(); if errors.peek().is_some() { - let trait_name = ty::item_path_str(tcx, object_trait.def_id); + let trait_name = ty::item_path_str(tcx, object_trait.def_id()); span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", trait_name); @@ -237,7 +232,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, object_trait: &ty::TyTrait<'tcx>, referent_ty: Ty<'tcx>) - -> Rc> + -> Rc> { // We can only make objects from sized types. fcx.register_builtin_bound( @@ -256,17 +251,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, referent_ty.repr(fcx.tcx()), object_trait_ty.repr(fcx.tcx())); - // Take the type parameters from the object type, but set - // the Self type (which is unknown, for the object type) - // to be the type we are casting from. - let mut object_substs = object_trait.principal.substs.clone(); - assert!(object_substs.self_ty().is_none()); - object_substs.types.push(SelfSpace, referent_ty); - // Create the obligation for casting from T to Trait. let object_trait_ref = - Rc::new(ty::TraitRef { def_id: object_trait.principal.def_id, - substs: object_substs }); + object_trait.principal_trait_ref_with_self_ty(referent_ty); let object_obligation = Obligation::new( ObligationCause::new(span, @@ -457,7 +444,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait_ref.repr(fcx.tcx()), self_ty.repr(fcx.tcx()), obligation.repr(fcx.tcx())); - let all_types = &trait_ref.substs.types; + let all_types = &trait_ref.substs().types; if all_types.iter().any(|&t| ty::type_is_error(t)) { } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { // This is kind of a hack: it frequently happens that some earlier @@ -476,7 +463,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // anyway. In that case, why inundate the user. if !fcx.tcx().sess.has_errors() { if fcx.ccx.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id) { + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { fcx.tcx().sess.span_err( obligation.cause.span, format!( diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 8c82429e1c226..e11f388b1160d 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -186,7 +186,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // There are special rules that apply to drop. if - fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) && + fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id()) && !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") { match self_ty.sty { @@ -200,7 +200,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } - if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) { + if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id()) { // This is checked in coherence. return } @@ -219,7 +219,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { traits::ObligationCause::new( item.span, fcx.body_id, - traits::ItemObligation(trait_ref.def_id)); + traits::ItemObligation(trait_ref.def_id())); // Find the supertrait bounds. This will add `int:Bar`. let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref); @@ -264,18 +264,18 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { /// /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated /// to the point where impl `A : Trait` is implemented). - pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { - let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id); + pub fn check_trait_ref(&mut self, trait_ref: &ty::PolyTraitRef<'tcx>) { + let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id()); - let bounds = trait_def.generics.to_bounds(self.tcx(), &trait_ref.substs); + let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs()); self.fcx.add_obligations_for_parameters( traits::ObligationCause::new( self.span, self.fcx.body_id, - traits::ItemObligation(trait_ref.def_id)), + traits::ItemObligation(trait_ref.def_id())), &bounds); - for &ty in trait_ref.substs.types.iter() { + for &ty in trait_ref.substs().types.iter() { self.check_traits_in_ty(ty); } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 16a77315bd50b..e9a3db1b0e6aa 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -64,7 +64,7 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, } ty_trait(ref t) => { - Some(t.principal.def_id) + Some(t.principal.def_id()) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | @@ -339,7 +339,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // Record all the trait items. for trait_ref in associated_traits.iter() { - self.add_trait_impl(trait_ref.def_id, impl_def_id); + self.add_trait_impl(trait_ref.def_id(), impl_def_id); } // For any methods that use a default implementation, add them to diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 1803bf766dda1..bb8efd2991070 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -55,7 +55,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { self.check_def_id(item.span, def_id); } ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => { - self.check_def_id(item.span, principal.def_id); + self.check_def_id(item.span, principal.def_id()); } _ => { span_err!(self.tcx.sess, item.span, E0118, diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 07a84846c47ad..6a24bdbb9f0ed 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -45,7 +45,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { } Some(trait_ref) => { - let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id); + let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id()); match (trait_def.unsafety, unsafety) { (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { self.tcx.sess.span_err( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 91947f67dd7f5..8930ae0116052 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -652,7 +652,7 @@ fn is_associated_type_valid_for_param(ty: Ty, if let ty::ty_param(param_ty) = ty.sty { let type_parameter = generics.types.get(param_ty.space, param_ty.idx); for trait_bound in type_parameter.bounds.trait_bounds.iter() { - if trait_bound.def_id == trait_id { + if trait_bound.def_id() == trait_id { return true } } @@ -1638,8 +1638,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::TraitRef { def_id: local_def(trait_id), - substs: (*substs).clone() }); + Rc::new(ty::bind(ty::TraitRef { def_id: local_def(trait_id), + substs: (*substs).clone() })); let def = ty::TypeParameterDef { space: subst::SelfSpace, @@ -2015,7 +2015,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, ¶m_bounds, span); - param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); + param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); param_bounds } @@ -2031,13 +2031,13 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, tcx, param_bounds.trait_bounds.as_slice(), |trait_ref| { - let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { span_err!(tcx.sess, span, E0129, "incompatible bounds on type parameter `{}`, \ bound `{}` does not allow unsized type", name_of_bounded_thing.user_string(tcx), - ppaux::trait_ref_to_string(tcx, &*trait_ref)); + trait_ref.user_string(tcx)); } true }); @@ -2057,14 +2057,14 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, trait_bounds, region_bounds } = astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice()); - let trait_bounds: Vec> = + let trait_bounds: Vec> = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_trait_ref(this, - &ExplicitRscope, - &bound.trait_ref, - Some(param_ty.to_ty(this.tcx())), - AllowEqConstraints::Allow) + astconv::instantiate_poly_trait_ref(this, + &ExplicitRscope, + bound, + Some(param_ty.to_ty(this.tcx())), + AllowEqConstraints::Allow) }) .collect(); let region_bounds: Vec = diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 8fe14bae0f5bc..a70058b977ead 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -777,13 +777,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { - let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id); + let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id()); let generics = &trait_def.generics; // Traits DO have a Self type parameter, but it is // erased from object types. assert!(!generics.types.is_empty_in(subst::SelfSpace) && - principal.substs.types.is_empty_in(subst::SelfSpace)); + principal.substs().types.is_empty_in(subst::SelfSpace)); // Traits never declare region parameters in the self // space. @@ -799,10 +799,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(bounds.region_bound, contra); self.add_constraints_from_substs( - principal.def_id, + principal.def_id(), generics.types.get_slice(subst::TypeSpace), generics.regions.get_slice(subst::TypeSpace), - &principal.substs, + principal.substs(), variance); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d0988af1cb473..49e45c9e56ca4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -281,7 +281,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it. match associated_trait { Some(ref t) => { - let trait_attrs = load_attrs(cx, tcx, t.def_id); + let trait_attrs = load_attrs(cx, tcx, t.def_id()); if trait_attrs.iter().any(|a| is_doc_hidden(a)) { return None } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d640f055388cb..9509986af4787 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -575,6 +575,12 @@ impl Clean for ty::BuiltinBound { } } +impl<'tcx> Clean for ty::PolyTraitRef<'tcx> { + fn clean(&self, cx: &DocContext) -> TyParamBound { + self.value.clean(cx) + } +} + impl<'tcx> Clean for ty::TraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { let tcx = match cx.tcx_opt() { @@ -1391,8 +1397,10 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) | - ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs }, - .. }) => { + ty::ty_trait(box ty::TyTrait { + principal: ty::Binder { value: ty::TraitRef { def_id: did, ref substs } }, + .. }) => + { let fqn = csearch::get_item_path(cx.tcx(), did); let fqn: Vec = fqn.into_iter().map(|i| { i.to_string() From 416e62924e200eb75dff4b7d622b5aa7ea8b691a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Dec 2014 06:13:42 -0500 Subject: [PATCH 11/24] Rename the code that replaces unbound variables to "freshen" rather than "skolemize" -- strictly speaking, this is not skolemization, because it is not discharging quantifiers. Also, the trait selection code will still be doing true skolemization, so it would be a confusing overlap of names. --- .../middle/infer/{skolemize.rs => freshen.rs} | 76 +++++++++--------- src/librustc/middle/infer/mod.rs | 12 +-- src/librustc/middle/traits/select.rs | 78 +++++++++---------- src/librustc/middle/ty.rs | 26 ++++--- src/librustc/util/ppaux.rs | 4 +- src/librustc_trans/trans/common.rs | 8 +- 6 files changed, 104 insertions(+), 100 deletions(-) rename src/librustc/middle/infer/{skolemize.rs => freshen.rs} (63%) diff --git a/src/librustc/middle/infer/skolemize.rs b/src/librustc/middle/infer/freshen.rs similarity index 63% rename from src/librustc/middle/infer/skolemize.rs rename to src/librustc/middle/infer/freshen.rs index 8336131c54acc..ebff854060cae 100644 --- a/src/librustc/middle/infer/skolemize.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -8,21 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Skolemization is the process of replacing unknown variables with fresh types. The idea is that -//! the type, after skolemization, contains no inference variables but instead contains either a +//! Freshening is the process of replacing unknown variables with fresh types. The idea is that +//! the type, after freshening, contains no inference variables but instead contains either a //! value for each variable or fresh "arbitrary" types wherever a variable would have been. //! -//! Skolemization is used primarily to get a good type for inserting into a cache. The result +//! Freshening is used primarily to get a good type for inserting into a cache. The result //! summarizes what the type inferencer knows "so far". The primary place it is used right now is //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type //! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending //! on what type that type variable is ultimately assigned, the match may or may not succeed. //! -//! Note that you should be careful not to allow the output of skolemization to leak to the user in -//! error messages or in any other form. Skolemization is only really useful as an internal detail. +//! Note that you should be careful not to allow the output of freshening to leak to the user in +//! error messages or in any other form. Freshening is only really useful as an internal detail. //! -//! __An important detail concerning regions.__ The skolemizer also replaces *all* regions with +//! __An important detail concerning regions.__ The freshener also replaces *all* regions with //! 'static. The reason behind this is that, in general, we do not take region relationships into //! account when making type-overloaded decisions. This is important because of the design of the //! region inferencer, which is not based on unification but rather on accumulating and then @@ -39,26 +39,26 @@ use std::collections::hash_map; use super::InferCtxt; use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; -pub struct TypeSkolemizer<'a, 'tcx:'a> { +pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - skolemization_count: uint, - skolemization_map: hash_map::HashMap>, + freshen_count: uint, + freshen_map: hash_map::HashMap>, } -impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> { - TypeSkolemizer { +impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { + TypeFreshener { infcx: infcx, - skolemization_count: 0, - skolemization_map: hash_map::HashMap::new(), + freshen_count: 0, + freshen_map: hash_map::HashMap::new(), } } - fn skolemize(&mut self, - opt_ty: Option>, - key: ty::InferTy, - skolemizer: F) - -> Ty<'tcx> where + fn freshen(&mut self, + opt_ty: Option>, + key: ty::InferTy, + freshener: F) + -> Ty<'tcx> where F: FnOnce(uint) -> ty::InferTy, { match opt_ty { @@ -66,12 +66,12 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { None => { } } - match self.skolemization_map.entry(key) { + match self.freshen_map.entry(key) { hash_map::Occupied(entry) => *entry.get(), hash_map::Vacant(entry) => { - let index = self.skolemization_count; - self.skolemization_count += 1; - let t = ty::mk_infer(self.infcx.tcx, skolemizer(index)); + let index = self.freshen_count; + self.freshen_count += 1; + let t = ty::mk_infer(self.infcx.tcx, freshener(index)); entry.set(t); t } @@ -79,7 +79,7 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { } } -impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> { self.infcx.tcx } @@ -106,37 +106,37 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.skolemize(self.infcx.type_variables.borrow().probe(v), + self.freshen(self.infcx.type_variables.borrow().probe(v), ty::TyVar(v), - ty::SkolemizedTy) + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::IntVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::FloatVar(v), + ty::FreshIntTy) } - ty::ty_infer(ty::SkolemizedTy(c)) | - ty::ty_infer(ty::SkolemizedIntTy(c)) => { - if c >= self.skolemization_count { + ty::ty_infer(ty::FreshTy(c)) | + ty::ty_infer(ty::FreshIntTy(c)) => { + if c >= self.freshen_count { self.tcx().sess.bug( - format!("Encountered a skolemized type with id {} \ + format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, - self.skolemization_count).as_slice()); + self.freshen_count).as_slice()); } t } ty::ty_open(..) => { - self.tcx().sess.bug("Cannot skolemize an open existential type"); + self.tcx().sess.bug("Cannot freshen an open existential type"); } ty::ty_bool | diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 80508a8f16f1f..c58b99e0ae2b7 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -19,7 +19,7 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use self::fixup_err::*; pub use middle::ty::IntVarValue; -pub use self::skolemize::TypeSkolemizer; +pub use self::freshen::TypeFreshener; use middle::subst; use middle::subst::Substs; @@ -57,7 +57,7 @@ pub mod lattice; pub mod lub; pub mod region_inference; pub mod resolve; -mod skolemize; +mod freshen; pub mod sub; pub mod type_variable; pub mod unify; @@ -505,8 +505,8 @@ pub struct CombinedSnapshot { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn skolemize>(&self, t: T) -> T { - t.fold_with(&mut self.skolemizer()) + pub fn freshen>(&self, t: T) -> T { + t.fold_with(&mut self.freshener()) } pub fn type_var_diverges(&'a self, ty: Ty) -> bool { @@ -516,8 +516,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn skolemizer<'b>(&'b self) -> TypeSkolemizer<'b, 'tcx> { - skolemize::TypeSkolemizer::new(self) + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { + freshen::TypeFreshener::new(self) } pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 86435267be002..ce59f5285dbc7 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -30,7 +30,7 @@ use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::ty::{mod, Ty, RegionEscape}; use middle::infer; -use middle::infer::{InferCtxt, TypeSkolemizer}; +use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use std::cell::RefCell; use std::collections::hash_map::HashMap; @@ -44,12 +44,12 @@ pub struct SelectionContext<'cx, 'tcx:'cx> { param_env: &'cx ty::ParameterEnvironment<'tcx>, typer: &'cx (Typer<'tcx>+'cx), - /// Skolemizer used specifically for skolemizing entries on the + /// Freshener used specifically for skolemizing entries on the /// obligation stack. This ensures that all entries on the stack /// at one time will have the same set of skolemized entries, /// which is important for checking for trait bounds that /// recursively require themselves. - skolemizer: TypeSkolemizer<'cx, 'tcx>, + freshener: TypeFreshener<'cx, 'tcx>, /// If true, indicates that the evaluation should be conservative /// and consider the possibility of types outside this crate. @@ -73,8 +73,8 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { obligation: &'prev TraitObligation<'tcx>, /// Trait ref from `obligation` but skolemized with the - /// selection-context's skolemizer. Used to check for recursion. - skol_trait_ref: Rc>, + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: Rc>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } @@ -172,7 +172,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: false, } } @@ -185,7 +185,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: true, } } @@ -347,16 +347,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.skol_trait_ref.value.input_types(); - let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t)); + let input_types = stack.fresh_trait_ref.value.input_types(); + let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t)); if unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.skol_trait_ref.value.def_id == prev.skol_trait_ref.value.def_id)) + |prev| stack.fresh_trait_ref.value.def_id == prev.fresh_trait_ref.value.def_id)) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToAmbig; } @@ -373,19 +373,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Option>>` is `Send` if `Box>` is // `Send`. // - // Note that we do this comparison using the `skol_trait_ref` + // Note that we do this comparison using the `fresh_trait_ref` // fields. Because these have all been skolemized using - // `self.skolemizer`, we can be sure that (a) this will not + // `self.freshener`, we can be sure that (a) this will not // affect the inferencer state and (b) that if we see two // skolemized types with the same index, they refer to the // same unbound type variable. if stack.iter() .skip(1) // skip top-most frame - .any(|prev| stack.skol_trait_ref == prev.skol_trait_ref) + .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref) { debug!("evaluate_stack({}) --> recursive", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToOk; } @@ -445,20 +445,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Check the cache. Note that we skolemize the trait-ref - // separately rather than using `stack.skol_trait_ref` -- this + // separately rather than using `stack.fresh_trait_ref` -- this // is because we want the unbound variables to be replaced // with fresh skolemized types starting from index 0. - let cache_skol_trait_ref = - self.infcx.skolemize(stack.obligation.trait_ref.clone()); - debug!("candidate_from_obligation(cache_skol_trait_ref={}, obligation={})", - cache_skol_trait_ref.repr(self.tcx()), + let cache_fresh_trait_ref = + self.infcx.freshen(stack.obligation.trait_ref.clone()); + debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})", + cache_fresh_trait_ref.repr(self.tcx()), stack.repr(self.tcx())); assert!(!stack.obligation.trait_ref.has_escaping_regions()); - match self.check_candidate_cache(cache_skol_trait_ref.clone()) { + match self.check_candidate_cache(cache_fresh_trait_ref.clone()) { Some(c) => { - debug!("CACHE HIT: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), + debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), c.repr(self.tcx())); return c; } @@ -467,9 +467,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If no match, compute result and insert into cache. let candidate = self.candidate_from_obligation_no_cache(stack); - debug!("CACHE MISS: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); - self.insert_candidate_cache(cache_skol_trait_ref, candidate.clone()); + debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); + self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone()); candidate } @@ -569,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn pick_candidate_cache(&self, - cache_skol_trait_ref: &Rc>) + cache_fresh_trait_ref: &Rc>) -> &SelectionCache<'tcx> { // High-level idea: we have to decide whether to consult the @@ -591,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_skol_trait_ref.value.input_types().iter().any( + cache_fresh_trait_ref.value.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_skol_trait_ref.value.input_types().iter().any( + cache_fresh_trait_ref.value.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -615,21 +615,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn check_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>) + cache_fresh_trait_ref: Rc>) -> Option>> { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_skol_trait_ref).map(|c| (*c).clone()) + hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone()) } fn insert_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>, + cache_fresh_trait_ref: Rc>, candidate: SelectionResult<'tcx, Candidate<'tcx>>) { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let mut hashmap = cache.hashmap.borrow_mut(); - hashmap.insert(cache_skol_trait_ref, candidate); + hashmap.insert(cache_fresh_trait_ref, candidate); } fn assemble_candidates<'o>(&mut self, @@ -1269,8 +1269,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::ty_open(_) | - ty::ty_infer(ty::SkolemizedTy(_)) | - ty::ty_infer(ty::SkolemizedIntTy(_)) => { + ty::ty_infer(ty::FreshTy(_)) | + ty::ty_infer(ty::FreshIntTy(_)) => { self.tcx().sess.bug( format!( "asked to assemble builtin bounds of unexpected type: {}", @@ -1831,11 +1831,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { - let skol_trait_ref = obligation.trait_ref.fold_with(&mut self.skolemizer); + let fresh_trait_ref = obligation.trait_ref.fold_with(&mut self.freshener); TraitObligationStack { obligation: obligation, - skol_trait_ref: skol_trait_ref, + fresh_trait_ref: fresh_trait_ref, previous: previous_stack.map(|p| p), // FIXME variance } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ee4097b4d0a9c..a25e4087905dd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1538,12 +1538,16 @@ pub enum InferTy { TyVar(TyVid), IntVar(IntVid), FloatVar(FloatVid), - SkolemizedTy(uint), + + /// A `FreshTy` is one that is generated as a replacement for an + /// unbound type variable. This is convenient for caching etc. See + /// `middle::infer::freshen` for more details. + FreshTy(uint), // FIXME -- once integral fallback is impl'd, we should remove // this type. It's only needed to prevent spurious errors for // integers whose type winds up never being constrained. - SkolemizedIntTy(uint), + FreshIntTy(uint), } impl Copy for InferTy {} @@ -1610,8 +1614,8 @@ impl fmt::Show for InferTy { TyVar(ref v) => v.fmt(f), IntVar(ref v) => v.fmt(f), FloatVar(ref v) => v.fmt(f), - SkolemizedTy(v) => write!(f, "SkolemizedTy({})", v), - SkolemizedIntTy(v) => write!(f, "SkolemizedIntTy({})", v), + FreshTy(v) => write!(f, "FreshTy({})", v), + FreshIntTy(v) => write!(f, "FreshIntTy({})", v), } } } @@ -2986,7 +2990,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } // Scalar and unique types are sendable, and durable - ty_infer(ty::SkolemizedIntTy(_)) | + ty_infer(ty::FreshIntTy(_)) | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char => { TC::None @@ -3592,10 +3596,10 @@ pub fn type_is_integral(ty: Ty) -> bool { } } -pub fn type_is_skolemized(ty: Ty) -> bool { +pub fn type_is_fresh(ty: Ty) -> bool { match ty.sty { - ty_infer(SkolemizedTy(_)) => true, - ty_infer(SkolemizedIntTy(_)) => true, + ty_infer(FreshTy(_)) => true, + ty_infer(FreshIntTy(_)) => true, _ => false } } @@ -4428,8 +4432,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(), - ty_infer(SkolemizedTy(_)) => "skolemized type".to_string(), - ty_infer(SkolemizedIntTy(_)) => "skolemized integral type".to_string(), + ty_infer(FreshTy(_)) => "skolemized type".to_string(), + ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -5594,7 +5598,7 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. - let open_ty = ty::mk_infer(tcx, SkolemizedTy(0)); + let open_ty = ty::mk_infer(tcx, FreshTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { let substs = principal.substs().with_self_ty(open_ty); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index afa7ce1867554..6c00aa546f387 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -374,8 +374,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty::IntVar(ref vid) if print_var_ids => vid.repr(cx), ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx), ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"), - ty::SkolemizedTy(v) => format!("SkolemizedTy({})", v), - ty::SkolemizedIntTy(v) => format!("SkolemizedIntTy({})", v) + ty::FreshTy(v) => format!("FreshTy({})", v), + ty::FreshIntTy(v) => format!("FreshIntTy({})", v) } } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index ab18a05a2511f..a8e88eca0e19f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -848,12 +848,12 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } - // Use skolemize to simultaneously replace all type variables with + // Use freshen to simultaneously replace all type variables with // their bindings and replace all regions with 'static. This is // sort of overkill because we do not expect there to be any - // unbound type variables, hence no skolemized types should ever - // be inserted. - let vtable = vtable.fold_with(&mut infcx.skolemizer()); + // unbound type variables, hence no `TyFresh` types should ever be + // inserted. + let vtable = vtable.fold_with(&mut infcx.freshener()); info!("Cache miss: {}", trait_ref.repr(ccx.tcx())); ccx.trait_cache().borrow_mut().insert(trait_ref, From ed4952ef392952dc4a7d0241386daf575dea5d6e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Dec 2014 06:37:42 -0500 Subject: [PATCH 12/24] Add (currently unused) helper routine for skolemizing bound regions. --- src/librustc/middle/infer/mod.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index c58b99e0ae2b7..4eda0d01ebb7b 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -90,6 +90,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> { RegionVarBindings<'a, 'tcx>, } +/// A map returned by `skolemize_bound_regions()` indicating the skolemized +/// region that each late-bound region was replaced with. +pub type SkolemizationMap = FnvHashMap; + /// Why did we require that the two types be related? /// /// See `error_reporting.rs` for more details @@ -698,9 +702,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.sub(a_is_expected, trace).poly_trait_refs(&*a, &*b).to_ures() }) } -} -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn skolemize_bound_regions(&self, + value: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + { + let (result_binder, map) = replace_late_bound_regions(self.tcx, value, |br, _| { + self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); + + debug!("skolemize_bound_regions(value={}, result={}, map={})", + value.repr(self.tcx), + result_binder.value.repr(self.tcx), + map.repr(self.tcx)); + + (result_binder.value, map) + } + pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { self.type_variables .borrow_mut() From 1205fd88df2b87c682f2e98e30ba9e2d8d44d656 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Dec 2014 11:28:35 -0500 Subject: [PATCH 13/24] Centralize on using `Binder` to introduce new binding levels, rather than having FnSig carry an implicit binding level. This means that we be more typesafe in general, since things that instantiate bound regions can drop the Binder to reflect that. --- src/librustc/metadata/decoder.rs | 4 +- src/librustc/metadata/tydecode.rs | 14 +- src/librustc/metadata/tyencode.rs | 14 +- src/librustc/middle/astencode.rs | 10 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/fast_reject.rs | 6 +- src/librustc/middle/infer/combine.rs | 74 ++++++++- src/librustc/middle/infer/equate.rs | 15 +- src/librustc/middle/infer/error_reporting.rs | 2 +- src/librustc/middle/infer/glb.rs | 10 +- .../middle/infer/higher_ranked/mod.rs | 139 +++++------------ src/librustc/middle/infer/lub.rs | 10 +- src/librustc/middle/infer/mod.rs | 28 ++-- src/librustc/middle/infer/sub.rs | 10 +- src/librustc/middle/intrinsicck.rs | 4 +- src/librustc/middle/liveness.rs | 1 + src/librustc/middle/privacy.rs | 8 +- src/librustc/middle/traits/coherence.rs | 14 +- src/librustc/middle/traits/select.rs | 34 ++--- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty.rs | 140 ++++++++---------- src/librustc/middle/ty_fold.rs | 48 +----- src/librustc/util/ppaux.rs | 54 ++++--- src/librustc_driver/test.rs | 4 +- src/librustc_trans/trans/base.rs | 22 +-- src/librustc_trans/trans/callee.rs | 22 +-- src/librustc_trans/trans/closure.rs | 6 +- src/librustc_trans/trans/debuginfo.rs | 40 ++--- src/librustc_trans/trans/expr.rs | 4 +- src/librustc_trans/trans/foreign.rs | 23 ++- src/librustc_trans/trans/glue.rs | 4 +- src/librustc_trans/trans/intrinsic.rs | 2 +- src/librustc_trans/trans/meth.rs | 8 +- src/librustc_trans/trans/type_of.rs | 8 +- src/librustc_typeck/astconv.rs | 38 ++--- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 19 +-- src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 28 ++-- src/librustc_typeck/check/mod.rs | 38 ++--- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/check/vtable.rs | 4 +- src/librustc_typeck/check/wf.rs | 22 +-- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 24 +-- src/librustc_typeck/lib.rs | 8 +- src/librustc_typeck/variance.rs | 6 +- src/librustdoc/clean/mod.rs | 22 +-- 48 files changed, 462 insertions(+), 545 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 1b3a6c0e6ba39..0625c50d6721f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -429,7 +429,7 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd, { let item_doc = lookup_item(id, cdata.data()); reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { - Rc::new(ty::bind(doc_trait_ref(tp, tcx, cdata))) + Rc::new(ty::Binder(doc_trait_ref(tp, tcx, cdata))) }) } @@ -704,7 +704,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc, cdata: Cmd, id: ast::Nod let name = item_name(&*intr, item); let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty { ty::ty_bare_fn(ref f) => - (Some(ctor_ty), f.sig.inputs.clone(), None), + (Some(ctor_ty), f.sig.0.inputs.clone(), None), _ => { // Nullary or struct enum variant. let mut arg_names = Vec::new(); let arg_tys = get_struct_fields(intr.clone(), cdata, did.node) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3d0b63139e4bc..f3d700f013d81 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -414,7 +414,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { } 'x' => { assert_eq!(next(st), '['); - let trait_ref = ty::bind(parse_trait_ref(st, |x,y| conv(x,y))); + let trait_ref = ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))); let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, trait_ref, bounds); @@ -603,7 +603,7 @@ fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, } } -fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<'tcx> { +fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnSig<'tcx> { assert_eq!(next(st), '['); let mut inputs = Vec::new(); while peek(st) != ']' { @@ -622,9 +622,9 @@ fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<' } _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y))) }; - ty::FnSig {inputs: inputs, - output: output, - variadic: variadic} + ty::Binder(ty::FnSig {inputs: inputs, + output: output, + variadic: variadic}) } // Rust metadata parsing @@ -669,7 +669,7 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => ty::Predicate::Trait(Rc::new(ty::bind(parse_trait_ref(st, conv)))), + 't' => ty::Predicate::Trait(Rc::new(ty::Binder(parse_trait_ref(st, conv)))), 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), parse_ty(st, |x,y| conv(x,y))), 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), @@ -764,7 +764,7 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) } 'I' => { param_bounds.trait_bounds.push( - Rc::new(ty::bind(parse_trait_ref(st, |x,y| conv(x,y))))); + Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index fd13ea57e6be0..c6218e6fe9478 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -251,7 +251,7 @@ fn enc_sty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { mywrite!(w, "x["); - enc_trait_ref(w, cx, &principal.value); + enc_trait_ref(w, cx, &principal.0); enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } @@ -351,18 +351,18 @@ pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, } fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, - fsig: &ty::FnSig<'tcx>) { + fsig: &ty::PolyFnSig<'tcx>) { mywrite!(w, "["); - for ty in fsig.inputs.iter() { + for ty in fsig.0.inputs.iter() { enc_ty(w, cx, *ty); } mywrite!(w, "]"); - if fsig.variadic { + if fsig.0.variadic { mywrite!(w, "V"); } else { mywrite!(w, "N"); } - match fsig.output { + match fsig.0.output { ty::FnConverging(result_type) => { enc_ty(w, cx, result_type); } @@ -401,7 +401,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); - enc_trait_ref(w, cx, &tp.value); + enc_trait_ref(w, cx, &tp.0); } mywrite!(w, "."); @@ -425,7 +425,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, match *p { ty::Predicate::Trait(ref trait_ref) => { mywrite!(w, "t"); - enc_trait_ref(w, cx, &trait_ref.value); + enc_trait_ref(w, cx, &trait_ref.0); } ty::Predicate::Equate(a, b) => { mywrite!(w, "e"); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3f0e28589fc54..0021533a2bbe6 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTypeParam", 2, 1, |this| { this.emit_struct("MethodParam", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &p.trait_ref.value)) + Ok(this.emit_trait_ref(ecx, &p.trait_ref.0)) })); try!(this.emit_struct_field("method_num", 0, |this| { this.emit_uint(p.method_num) @@ -901,7 +901,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTraitObject", 3, 1, |this| { this.emit_struct("MethodObject", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &o.trait_ref.value)) + Ok(this.emit_trait_ref(ecx, &o.trait_ref.0)) })); try!(this.emit_struct_field("object_trait_id", 0, |this| { Ok(this.emit_def_id(o.object_trait_id)) @@ -1113,7 +1113,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg(0, |this| { try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &principal.value)) + Ok(this.emit_trait_ref(ecx, &principal.0)) })); this.emit_struct_field("bounds", 1, |this| { Ok(this.emit_existential_bounds(ecx, b)) @@ -1277,7 +1277,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_trait_ref(ecx, &trait_ref.value); + rbml_w.emit_trait_ref(ecx, &trait_ref.0); }) }) } @@ -1552,7 +1552,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Rc> { - Rc::new(ty::bind(self.read_opaque(|this, doc| { + Rc::new(ty::Binder(self.read_opaque(|this, doc| { let ty = tydecode::parse_trait_ref_data( doc.data, dcx.cdata.cnum, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 41020df63995e..8b0df4e69cd8e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -265,7 +265,7 @@ impl OverloadedCallType { } Some(ref trait_ref) => (*trait_ref).clone(), }; - OverloadedCallType::from_trait_id(tcx, trait_ref.value.def_id) + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id()) } fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId) diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 2be5e46fcbb68..5c0d4b4841ee3 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -60,7 +60,7 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal.value.def_id)) + Some(TraitSimplifiedType(trait_info.principal.def_id())) } ty::ty_struct(def_id, _) => { Some(StructSimplifiedType(def_id)) @@ -83,10 +83,10 @@ pub fn simplify_type(tcx: &ty::ctxt, Some(TupleSimplifiedType(tys.len())) } ty::ty_closure(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_bare_fn(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_param(_) => { if can_simplify_params { diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 1681731005db8..82ddbcee5a72e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -195,7 +195,7 @@ pub trait Combine<'tcx> { b: &ty::BareFnTy<'tcx>) -> cres<'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.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); Ok(ty::BareFnTy {unsafety: unsafety, abi: abi, sig: sig}) @@ -222,7 +222,7 @@ pub trait Combine<'tcx> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let onceness = try!(self.oncenesses(a.onceness, b.onceness)); let bounds = try!(self.existential_bounds(a.bounds, b.bounds)); - let sig = try!(self.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); let abi = try!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { unsafety: unsafety, @@ -234,7 +234,43 @@ pub trait Combine<'tcx> { }) } - 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>) -> cres<'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.as_slice(), + b.inputs.as_slice())); + + 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: Combine<'tcx>>(combiner: &C, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> cres<'tcx, Vec>> + { + 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>) -> cres<'tcx, Ty<'tcx>> { self.contratys(a, b).and_then(|t| Ok(t)) @@ -312,14 +348,36 @@ pub trait Combine<'tcx> { } } - fn poly_trait_refs(&self, - a: &ty::PolyTraitRef<'tcx>, - b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>>; + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'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>; +} + +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>> + { + combiner.trait_refs(a, b) + } +} + +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>> + { + combiner.fn_sigs(a, b) + } +} + #[deriving(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -424,7 +482,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); - let principal = try!(this.poly_trait_refs(&a_.principal, &b_.principal)); + 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)) } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 79fbc33f2a1df..2a4d20f4dd379 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -133,17 +133,10 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> { - try!(self.sub().fn_sigs(a, b)); - self.sub().fn_sigs(b, a) - } - - fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>> - { - try!(self.sub().poly_trait_refs(a, b)); - self.sub().poly_trait_refs(b, a) + try!(self.sub().binders(a, b)); + self.sub().binders(b, a) } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 89d6a7df05098..d1253e0b6976b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1653,7 +1653,7 @@ impl<'tcx> Resolvable<'tcx> for Rc> { Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { - ty::trait_ref_contains_error(&self.value) + ty::trait_ref_contains_error(&self.0) } } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index f751931a9412e..434be32fe5fa7 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -121,13 +121,9 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { super_lattice_tys(self, a, b) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_glb(a, b) - } - - fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'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 93a4d7c2f46d9..dcc365fad18ee 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,29 +11,24 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{combine, CombinedSnapshot, cres, InferCtxt, HigherRankedType}; -use super::combine::Combine; +use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType}; +use super::combine::{Combine, Combineable}; -use middle::ty::{mod, Ty, replace_late_bound_regions}; -use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; +use middle::ty::{mod, Binder}; +use middle::ty_fold::{mod, TypeFoldable}; use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; -use util::ppaux::{bound_region_to_string, Repr}; - -pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> + - TypeFoldable<'tcx> + Repr<'tcx> { - fn super_combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; -} +use util::ppaux::Repr; pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; - fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; - fn higher_ranked_glb(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; } trait InferCtxtExt<'tcx> { @@ -47,8 +42,9 @@ trait InferCtxtExt<'tcx> { impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { - fn higher_ranked_sub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) + -> cres<'tcx, Binder> + where T : Combineable<'tcx> { debug!("higher_ranked_sub(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); @@ -74,13 +70,14 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Second, we instantiate each bound region in the supertype with a // fresh concrete region. - let (b_prime, skol_map) = skolemize_regions(self.infcx(), b, snapshot); + let (b_prime, skol_map) = + self.infcx().skolemize_late_bound_regions(b, snapshot); debug!("a_prime={}", a_prime.repr(self.tcx())); debug!("b_prime={}", b_prime.repr(self.tcx())); // Compare types now that bound regions have been replaced. - let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); + let result = try!(Combineable::combine(self, &a_prime, &b_prime)); // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". @@ -102,12 +99,12 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C debug!("higher_ranked_sub: OK result={}", result.repr(self.tcx())); - Ok(result) + Ok(ty::Binder(result)) }); } - fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". @@ -123,7 +120,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Collect constraints. let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); let result0 = self.infcx().resolve_type_vars_if_possible(&result0); debug!("lub result0 = {}", result0.repr(self.tcx())); @@ -143,7 +140,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C b.repr(self.tcx()), result1.repr(self.tcx())); - Ok(result1) + Ok(ty::Binder(result1)) }); fn generalize_region(infcx: &InferCtxt, @@ -196,8 +193,8 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx> { debug!("{}.higher_ranked_glb({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); @@ -217,7 +214,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Collect constraints. let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); let result0 = self.infcx().resolve_type_vars_if_possible(&result0); debug!("glb result0 = {}", result0.repr(self.tcx())); @@ -239,7 +236,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C b.repr(self.tcx()), result1.repr(self.tcx())); - Ok(result1) + Ok(ty::Binder(result1)) }); fn generalize_region(infcx: &InferCtxt, @@ -334,59 +331,6 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } -impl<'tcx> HigherRankedCombineable<'tcx> for ty::FnSig<'tcx> { - fn super_combine>(combiner: &C, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> - { - if a.variadic != b.variadic { - return Err(ty::terr_variadic_mismatch( - combine::expected_found(combiner, a.variadic, b.variadic))); - } - - let inputs = try!(argvecs(combiner, - a.inputs.as_slice(), - b.inputs.as_slice())); - - let output = try!(match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(try!(combiner.tys(a_ty, b_ty)))), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(ty::terr_convergence_mismatch( - combine::expected_found(combiner, a != ty::FnDiverging, b != ty::FnDiverging))), - }); - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - - - fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> - { - 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) - } - } - } -} - -impl<'tcx> HigherRankedCombineable<'tcx> for ty::PolyTraitRef<'tcx> { - fn super_combine>(combiner: &C, - a: &ty::PolyTraitRef<'tcx>, - b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>> - { - Ok(ty::bind(try!(combiner.trait_refs(&a.value, &b.value)))) - } -} - fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, map: &FnvHashMap) -> Vec { @@ -407,11 +351,14 @@ fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { } } -fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> T where - T: HigherRankedFoldable<'tcx>, - F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, +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, { - value.fold_contents(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| { + unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables @@ -508,26 +455,6 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { } } -fn skolemize_regions<'a,'tcx,HR>(infcx: &InferCtxt<'a,'tcx>, - value: &HR, - snapshot: &CombinedSnapshot) - -> (HR, FnvHashMap) - where HR : HigherRankedFoldable<'tcx> -{ - replace_late_bound_regions(infcx.tcx, value, |br, _| { - let skol = - infcx.region_vars.new_skolemized( - br, - &snapshot.region_vars_snapshot); - - debug!("Bound region {} skolemized to {}", - bound_region_to_string(infcx.tcx, "", false, br), - skol); - - skol - }) -} - fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, skol_map: &FnvHashMap, snapshot: &CombinedSnapshot) diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index e142e3dbe443b..f4909b2889163 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -113,17 +113,13 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_lub(a, b) - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } - fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'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 4eda0d01ebb7b..edd5c8b854e1f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -26,7 +26,7 @@ use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::replace_late_bound_regions; use middle::ty::{mod, Ty}; -use middle::ty_fold::{HigherRankedFoldable, TypeFolder, TypeFoldable}; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use std::cell::{RefCell}; use std::rc::Rc; use syntax::ast; @@ -35,7 +35,7 @@ use syntax::codemap::Span; use util::common::indent; use util::nodemap::FnvHashMap; use util::ppaux::{ty_to_string}; -use util::ppaux::{trait_ref_to_string, Repr}; +use util::ppaux::{Repr, UserString}; use self::coercion::Coerce; use self::combine::{Combine, CombineFields}; @@ -699,26 +699,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).poly_trait_refs(&*a, &*b).to_ures() + self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures() }) } - pub fn skolemize_bound_regions(&self, - value: &ty::Binder, - snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) - where T : TypeFoldable<'tcx> + pub fn skolemize_late_bound_regions(&self, + value: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> { - let (result_binder, map) = replace_late_bound_regions(self.tcx, value, |br, _| { + let (result, map) = replace_late_bound_regions(self.tcx, value, |br, _| { self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) }); debug!("skolemize_bound_regions(value={}, result={}, map={})", value.repr(self.tcx), - result_binder.value.repr(self.tcx), + result.repr(self.tcx), map.repr(self.tcx)); - (result_binder.value, map) + (result, map) } pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { @@ -828,7 +828,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn trait_ref_to_string(&self, t: &Rc>) -> String { let t = self.resolve_type_vars_if_possible(&**t); - trait_ref_to_string(self.tcx, &t) + t.user_string(self.tcx) } pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { @@ -982,9 +982,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &T) + value: &ty::Binder) -> (T, FnvHashMap) - where T : HigherRankedFoldable<'tcx> + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::replace_late_bound_regions( self.tcx, diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index e7b7791cc2a84..2b8adfb7c1eeb 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -155,13 +155,9 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_sub(a, b) - } - - fn poly_trait_refs(&self, a: &ty::PolyTraitRef<'tcx>, b: &ty::PolyTraitRef<'tcx>) - -> cres<'tcx, ty::PolyTraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> + { self.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index acfdf6fefb55f..ea19111ce3d67 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -124,8 +124,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { let typ = ty::node_id_to_type(self.tcx, expr.id); match typ.sty { ty_bare_fn(ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - if let ty::FnConverging(to) = bare_fn_ty.sig.output { - let from = bare_fn_ty.sig.inputs[0]; + if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { + let from = bare_fn_ty.sig.0.inputs[0]; self.check_transmute(expr.span, from, to, expr.id); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c76d9bc6b1faa..4df655882b155 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1534,6 +1534,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { .unwrap() .closure_type .sig + .0 .output, _ => ty::ty_fn_ret(fn_ty) } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index b0d62644ca510..67e9d2fee58f4 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -257,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { }; let tr = ty::impl_trait_ref(self.tcx, local_def(item.id)); let public_trait = tr.clone().map_or(false, |tr| { - !is_local(tr.value.def_id) || - self.exported_items.contains(&tr.value.def_id.node) + !is_local(tr.def_id()) || + self.exported_items.contains(&tr.def_id().node) }); if public_ty || public_trait { @@ -407,7 +407,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.value.def_id) + self.def_privacy(t.def_id()) } None => { debug!("privacy - found a method {}", @@ -432,7 +432,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.value.def_id) + self.def_privacy(t.def_id()) } None => { debug!("privacy - found a typedef {}", diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 011f86e2810ae..3b759b042f2ac 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -18,6 +18,7 @@ use middle::subst; use middle::subst::Subst; use middle::ty::{mod, Ty}; use middle::infer::{mod, InferCtxt}; +use std::rc::Rc; use syntax::ast; use syntax::codemap::DUMMY_SP; use util::ppaux::Repr; @@ -42,13 +43,14 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, let impl1_trait_ref = infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP, infer::FnCall, - &impl1_trait_ref).0; + &*impl1_trait_ref).0; // Determine whether `impl2` can provide an implementation for those // same types. let param_env = ty::empty_parameter_environment(); let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx); - let obligation = Obligation::new(ObligationCause::dummy(), impl1_trait_ref); + let obligation = Obligation::new(ObligationCause::dummy(), + Rc::new(ty::Binder(impl1_trait_ref))); debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); selcx.evaluate_impl(impl2_def_id, &obligation) } @@ -65,15 +67,15 @@ pub fn impl_is_local(tcx: &ty::ctxt, debug!("trait_ref={}", trait_ref.repr(tcx)); // If the trait is local to the crate, ok. - if trait_ref.value.def_id.krate == ast::LOCAL_CRATE { + if trait_ref.def_id().krate == ast::LOCAL_CRATE { debug!("trait {} is local to current crate", - trait_ref.value.def_id.repr(tcx)); + trait_ref.def_id().repr(tcx)); return true; } // Otherwise, at least one of the input types must be local to the // crate. - trait_ref.value.input_types().iter().any(|&t| ty_is_local(tcx, t)) + trait_ref.0.input_types().iter().any(|&t| ty_is_local(tcx, t)) } pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -143,7 +145,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_trait(ref tt) => { - tt.principal.value.def_id.krate == ast::LOCAL_CRATE + tt.principal.def_id().krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index ce59f5285dbc7..e0a40901ee851 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -347,13 +347,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.fresh_trait_ref.value.input_types(); + let input_types = stack.fresh_trait_ref.0.input_types(); let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t)); if unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.fresh_trait_ref.value.def_id == prev.fresh_trait_ref.value.def_id)) + |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", stack.fresh_trait_ref.repr(self.tcx())); @@ -591,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_fresh_trait_ref.value.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_fresh_trait_ref.value.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -648,7 +648,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.value.def_id) { + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id()) { Some(ty::BoundCopy) => { debug!("obligation self ty is {}", obligation.self_ty().repr(self.tcx())); @@ -731,7 +731,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.fn_family_trait_kind(obligation.trait_ref.value.def_id) { + let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -779,7 +779,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We provide a `Fn` impl for fn pointers. There is no need to provide // the other traits (e.g. `FnMut`) since those are provided by blanket // impls. - if Some(obligation.trait_ref.value.def_id) != self.tcx().lang_items.fn_trait() { + if Some(obligation.trait_ref.def_id()) != self.tcx().lang_items.fn_trait() { return Ok(()); } @@ -793,11 +793,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: _, output: ty::FnConverging(_), variadic: false - } + }) }) => { candidates.vec.push(FnPointerCandidate); } @@ -814,7 +814,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - let all_impls = self.all_impls(obligation.trait_ref.value.def_id); + let all_impls = self.all_impls(obligation.trait_ref.def_id()); for &impl_def_id in all_impls.iter() { self.infcx.probe(|| { match self.match_impl(impl_def_id, obligation) { @@ -1083,7 +1083,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // bounds are required and thus we must fulfill. let tmp_tr = data.principal_trait_ref_with_self_ty(ty::mk_err()); for tr in util::supertraits(self.tcx(), tmp_tr) { - let td = ty::lookup_trait_def(self.tcx(), tr.value.def_id); + let td = ty::lookup_trait_def(self.tcx(), tr.def_id()); if td.bounds.builtin_bounds.contains(&bound) { return Ok(If(Vec::new())) @@ -1519,15 +1519,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec()); - let output_type = sig.output.unwrap(); + let arguments_tuple = ty::mk_tup(self.tcx(), sig.0.inputs.to_vec()); + let output_type = sig.0.output.unwrap(); let substs = Substs::new_trait( vec![arguments_tuple, output_type], vec![], vec![], self_ty); - let trait_ref = Rc::new(ty::bind(ty::TraitRef { + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: obligation.trait_ref.def_id(), substs: substs, })); @@ -1562,15 +1562,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let closure_sig = &closure_type.sig; - let arguments_tuple = closure_sig.inputs[0]; + let arguments_tuple = closure_sig.0.inputs[0]; let substs = Substs::new_trait( vec![arguments_tuple.subst(self.tcx(), substs), - closure_sig.output.unwrap().subst(self.tcx(), substs)], + closure_sig.0.output.unwrap().subst(self.tcx(), substs)], vec![], vec![], obligation.self_ty()); - let trait_ref = Rc::new(ty::bind(ty::TraitRef { + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: obligation.trait_ref.def_id(), substs: substs, })); diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 2daf5453745b5..27824ba5c6e77 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -274,7 +274,7 @@ pub fn poly_trait_ref_for_builtin_bound<'tcx>( { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Ok(Rc::new(ty::bind(ty::TraitRef { + Ok(Rc::new(ty::Binder(ty::TraitRef { def_id: def_id, substs: Substs::empty().with_self_ty(param_ty) }))) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a25e4087905dd..a24992e89e35d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -60,7 +60,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; use middle::traits::ObligationCause; use middle::traits; use middle::ty; -use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable}; +use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; use util::ppaux::{Repr, UserString}; @@ -908,7 +908,7 @@ pub fn type_escapes_depth(ty: Ty, depth: uint) -> bool { pub struct BareFnTy<'tcx> { pub unsafety: ast::Unsafety, pub abi: abi::Abi, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, } #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -917,7 +917,7 @@ pub struct ClosureTy<'tcx> { pub onceness: ast::Onceness, pub store: TraitStore, pub bounds: ExistentialBounds, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, pub abi: abi::Abi, } @@ -944,10 +944,6 @@ impl<'tcx> Copy for FnOutput<'tcx> {} /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a varidic function. (only true for foreign fns) -/// -/// Note that a `FnSig` introduces a level of region binding, to -/// account for late-bound parameters that appear in the types of the -/// fn's arguments or the fn's return type. #[deriving(Clone, PartialEq, Eq, Hash)] pub struct FnSig<'tcx> { pub inputs: Vec>, @@ -955,6 +951,8 @@ pub struct FnSig<'tcx> { pub variadic: bool } +pub type PolyFnSig<'tcx> = Binder>; + #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct ParamTy { pub space: subst::ParamSpace, @@ -1318,9 +1316,9 @@ impl<'tcx> TyTrait<'tcx> { /// you must give *some* self-type. A common choice is `mk_err()` /// or some skolemized type. pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) -> Rc> { - Rc::new(ty::bind(ty::TraitRef { - def_id: self.principal.value.def_id, - substs: self.principal.value.substs.with_self_ty(self_ty), + Rc::new(ty::Binder(ty::TraitRef { + def_id: self.principal.def_id(), + substs: self.principal.substs().with_self_ty(self_ty), })) } } @@ -1350,19 +1348,19 @@ pub type PolyTraitRef<'tcx> = Binder>; impl<'tcx> PolyTraitRef<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { - self.value.self_ty() + self.0.self_ty() } pub fn def_id(&self) -> ast::DefId { - self.value.def_id + self.0.def_id } pub fn substs(&self) -> &Substs<'tcx> { - &self.value.substs + &self.0.substs } pub fn input_types(&self) -> &[Ty<'tcx>] { - self.value.input_types() + self.0.input_types() } } @@ -1373,13 +1371,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// by the binder supplied to it; but a type is not a binder, so you /// must introduce an artificial one). #[deriving(Clone, PartialEq, Eq, Hash, Show)] -pub struct Binder { - pub value: T -} - -pub fn bind(value: T) -> Binder { - Binder { value: value } -} +pub struct Binder(pub T); #[deriving(Clone, PartialEq)] pub enum IntVarValue { @@ -2237,12 +2229,12 @@ impl FlagComputation { } } - fn add_fn_sig(&mut self, fn_sig: &FnSig) { + fn add_fn_sig(&mut self, fn_sig: &PolyFnSig) { let mut computation = FlagComputation::new(); - computation.add_tys(fn_sig.inputs[]); + computation.add_tys(fn_sig.0.inputs[]); - if let ty::FnConverging(output) = fn_sig.output { + if let ty::FnConverging(output) = fn_sig.0.output { computation.add_ty(output); } @@ -2385,11 +2377,11 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: input_args, output: ty::FnConverging(output), variadic: false - } + }) }) } @@ -2481,14 +2473,14 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { } ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } } ty_bare_fn(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } ty_closure(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } @@ -3857,15 +3849,15 @@ pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts pub fn fn_is_variadic(fty: Ty) -> bool { match fty.sty { - ty_bare_fn(ref f) => f.sig.variadic, - ty_closure(ref f) => f.sig.variadic, + ty_bare_fn(ref f) => f.sig.0.variadic, + ty_closure(ref f) => f.sig.0.variadic, ref s => { panic!("fn_is_variadic() called on non-fn type: {}", s) } } } -pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx FnSig<'tcx> { +pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { match fty.sty { ty_bare_fn(ref f) => &f.sig, ty_closure(ref f) => &f.sig, @@ -3886,7 +3878,7 @@ pub fn ty_fn_abi(fty: Ty) -> abi::Abi { // Type accessors for substructures of types pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] { - ty_fn_sig(fty).inputs.as_slice() + ty_fn_sig(fty).0.inputs.as_slice() } pub fn ty_closure_store(fty: Ty) -> TraitStore { @@ -3905,8 +3897,8 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore { pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> { match fty.sty { - ty_bare_fn(ref f) => f.sig.output, - ty_closure(ref f) => f.sig.output, + ty_bare_fn(ref f) => f.sig.0.output, + ty_closure(ref f) => f.sig.0.output, ref s => { panic!("ty_fn_ret() called on non-fn type: {}", s) } @@ -4801,7 +4793,7 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) &Some(ref t) => { let trait_ref = (*ty::node_id_to_trait_ref(cx, t.ref_id)).clone(); - Some(Rc::new(ty::bind(trait_ref))) + Some(Rc::new(ty::Binder(trait_ref))) } &None => None } @@ -5180,7 +5172,7 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_def.bounds.trait_bounds .iter() .map(|bound_trait_ref| { - ty::bind( + ty::Binder( ty::TraitRef::new(bound_trait_ref.def_id(), bound_trait_ref.substs().subst(tcx, trait_ref.substs()))) }) @@ -5515,18 +5507,6 @@ pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { subst::Substs { regions: subst::ErasedRegions, types: substs.types.fold_with(self) } } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - // The binder-id is only relevant to bound regions, which - // are erased at trans time. - ty::FnSig { - inputs: sig.inputs.fold_with(self), - output: sig.output.fold_with(self), - variadic: sig.variadic, - } - } } } @@ -5602,7 +5582,7 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { let substs = principal.substs().with_self_ty(open_ty); - vec!(Rc::new(ty::bind(ty::TraitRef::new(principal.def_id(), substs)))) + vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), substs)))) }); let param_bounds = ty::ParamBounds { @@ -5856,12 +5836,12 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. -pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { +pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { let mut state = sip::SipState::new(); helper(tcx, ty, svh, &mut state); return state.result(); - fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) { + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) { macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } ); macro_rules! hash( ($e:expr) => { $e.hash(state) } ); @@ -5894,7 +5874,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { let mt = |state: &mut sip::SipState, mt: mt| { mt.mutbl.hash(state); }; - let fn_sig = |state: &mut sip::SipState, sig: &FnSig| { + let fn_sig = |state: &mut sip::SipState, sig: &Binder>| { let sig = anonymize_late_bound_regions(tcx, sig); for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } if let ty::FnConverging(output) = sig.output { @@ -5974,7 +5954,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { hash!(bounds); let principal = anonymize_late_bound_regions(tcx, principal); - for subty in principal.substs().types.iter() { + for subty in principal.substs.types.iter() { helper(tcx, *subty, svh, state); } @@ -6065,7 +6045,7 @@ pub fn construct_parameter_environment<'tcx>( // let bounds = generics.to_bounds(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; + let bounds = liberate_late_bound_regions(tcx, free_id_scope, &ty::Binder(bounds)); // // Compute region bounds. For now, these relations are stored in a @@ -6321,12 +6301,12 @@ impl<'tcx> AutoDerefRef<'tcx> { /// Replace any late-bound regions bound in `value` with free variants attached to scope-id /// `scope_id`. -pub fn liberate_late_bound_regions<'tcx, HR>( +pub fn liberate_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, scope: region::CodeExtent, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions( tcx, value, @@ -6335,11 +6315,11 @@ pub fn liberate_late_bound_regions<'tcx, HR>( /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. -pub fn erase_late_bound_regions<'tcx, HR>( +pub fn erase_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0 } @@ -6352,8 +6332,12 @@ pub fn erase_late_bound_regions<'tcx, HR>( /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and /// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization. -pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR - where HR: HigherRankedFoldable<'tcx> { +pub fn anonymize_late_bound_regions<'tcx, T>( + tcx: &ctxt<'tcx>, + sig: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx>, +{ let mut counter = 0; replace_late_bound_regions(tcx, sig, |_, db| { counter += 1; @@ -6362,15 +6346,15 @@ pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR } /// Replaces the late-bound-regions in `value` that are bound by `value`. -pub fn replace_late_bound_regions<'tcx, HR, F>( +pub fn replace_late_bound_regions<'tcx, T, F>( tcx: &ty::ctxt<'tcx>, - value: &HR, + binder: &Binder, mut mapf: F) --> (HR, FnvHashMap) where - HR : HigherRankedFoldable<'tcx>, - F: FnMut(BoundRegion, DebruijnIndex) -> ty::Region, + -> (T, FnvHashMap) + where T : TypeFoldable<'tcx> + Repr<'tcx>, + F : FnMut(BoundRegion, DebruijnIndex) -> ty::Region, { - debug!("replace_late_bound_regions({})", value.repr(tcx)); + debug!("replace_late_bound_regions({})", binder.repr(tcx)); let mut map = FnvHashMap::new(); let value = { @@ -6389,11 +6373,9 @@ pub fn replace_late_bound_regions<'tcx, HR, F>( } }); - // Note: use `fold_contents` not `fold_with`. If we used - // `fold_with`, it would consider the late-bound regions bound - // by `value` to be bound, but we want to consider them as - // `free`. - value.fold_contents(&mut f) + // Note: fold the field `0`, not the binder, so that late-bound + // regions bound by `binder` are considered free. + binder.0.fold_with(&mut f) }; debug!("resulting map: {} value: {}", map, value.repr(tcx)); (value, map) @@ -6600,13 +6582,13 @@ impl<'tcx> RegionEscape for TraitRef<'tcx> { impl<'tcx,T:RegionEscape> RegionEscape for Binder { fn has_regions_escaping_depth(&self, depth: uint) -> bool { - self.value.has_regions_escaping_depth(depth + 1) + self.0.has_regions_escaping_depth(depth + 1) } } impl Binder { pub fn has_bound_regions(&self) -> bool { - self.value.has_regions_escaping_depth(0) + self.0.has_regions_escaping_depth(0) } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index da6ddf7461b35..6d6dc1d426ad6 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -93,8 +93,8 @@ pub trait TypeFolder<'tcx> { } fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { + sig: &ty::FnSig<'tcx>) + -> ty::FnSig<'tcx> { super_fold_fn_sig(self, sig) } @@ -183,7 +183,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { fn fold_with>(&self, folder: &mut F) -> ty::Binder { folder.enter_region_binder(); - let result = ty::bind(self.value.fold_with(folder)); + let result = ty::Binder(self.0.fold_with(folder)); folder.exit_region_binder(); result } @@ -532,16 +532,6 @@ pub fn super_fold_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, pub fn super_fold_fn_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T, sig: &ty::FnSig<'tcx>) -> ty::FnSig<'tcx> -{ - this.enter_region_binder(); - let result = super_fold_fn_sig_contents(this, sig); - this.exit_region_binder(); - result -} - -pub fn super_fold_fn_sig_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { ty::FnSig { inputs: sig.inputs.fold_with(this), output: sig.output.fold_with(this), @@ -696,34 +686,6 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } -/////////////////////////////////////////////////////////////////////////// -// Higher-ranked things - -/// Designates a "binder" for late-bound regions. -pub trait HigherRankedFoldable<'tcx>: Repr<'tcx> { - /// Folds the contents of `self`, ignoring the region binder created - /// by `self`. - fn fold_contents>(&self, folder: &mut F) -> Self; -} - -impl<'tcx> HigherRankedFoldable<'tcx> for ty::FnSig<'tcx> { - fn fold_contents>(&self, folder: &mut F) -> ty::FnSig<'tcx> { - super_fold_fn_sig_contents(folder, self) - } -} - -impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> HigherRankedFoldable<'tcx> for ty::Binder { - fn fold_contents>(&self, folder: &mut F) -> ty::Binder { - ty::bind(self.value.fold_with(folder)) - } -} - -impl<'tcx, T:HigherRankedFoldable<'tcx>> HigherRankedFoldable<'tcx> for Rc { - fn fold_contents>(&self, folder: &mut F) -> Rc { - Rc::new((**self).fold_contents(folder)) - } -} - /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -754,10 +716,6 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /// regions (aka "lifetimes") that are bound within a type are not /// visited by this folder; only regions that occur free will be /// visited by `fld_r`. -/// -/// (The distinction between "free" and "bound" is represented by -/// keeping track of each `FnSig` in the lexical context of the -/// current position of the fold.) pub struct RegionFolder<'a, 'tcx: 'a, F> where F: FnMut(ty::Region, uint) -> ty::Region { tcx: &'a ty::ctxt<'tcx>, current_depth: uint, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6c00aa546f387..134006bef0b75 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -23,7 +23,10 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; +use middle::ty_fold::TypeFoldable; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; use syntax::ast_map; @@ -40,7 +43,7 @@ pub trait Repr<'tcx> for Sized? { } /// Produces a string suitable for showing to the user. -pub trait UserString<'tcx> { +pub trait UserString<'tcx> : Repr<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String; } @@ -248,21 +251,12 @@ pub fn vec_map_to_string(ts: &[T], f: F) -> String where format!("[{}]", tstrs.connect(", ")) } -pub fn fn_sig_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::FnSig<'tcx>) -> String { - format!("fn{} -> {}", typ.inputs.repr(cx), typ.output.repr(cx)) -} - -pub fn trait_ref_to_string<'tcx>(cx: &ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>) -> String { - trait_ref.user_string(cx).to_string() -} - pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, ident: Option, - sig: &ty::FnSig<'tcx>) + sig: &ty::PolyFnSig<'tcx>) -> String { let mut s = String::new(); match unsafety { @@ -336,15 +330,15 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s: &mut String, bra: char, ket: char, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, bounds: &str) { s.push(bra); - let strs = sig.inputs + let strs = sig.0.inputs .iter() .map(|a| ty_to_string(cx, *a)) .collect::>(); s.push_str(strs.connect(", ").as_slice()); - if sig.variadic { + if sig.0.variadic { s.push_str(", ..."); } s.push(ket); @@ -354,7 +348,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s.push_str(bounds); } - match sig.output { + match sig.0.output { ty::FnConverging(t) => { if !ty::type_is_nil(t) { s.push_str(" -> "); @@ -1013,7 +1007,7 @@ impl<'tcx> Repr<'tcx> for ty::BareFnTy<'tcx> { impl<'tcx> Repr<'tcx> for ty::FnSig<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - fn_sig_to_string(tcx, self) + format!("fn{} -> {}", self.inputs.repr(tcx), self.output.repr(tcx)) } } @@ -1156,7 +1150,9 @@ impl<'tcx> UserString<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> UserString<'tcx> for ty::PolyTraitRef<'tcx> { +impl<'tcx, T> UserString<'tcx> for ty::Binder + where T : UserString<'tcx> + TypeFoldable<'tcx> +{ fn user_string(&self, tcx: &ctxt<'tcx>) -> String { // Replace any anonymous late-bound regions with named // variants, using gensym'd identifiers, so that we can @@ -1164,7 +1160,7 @@ impl<'tcx> UserString<'tcx> for ty::PolyTraitRef<'tcx> { // the output. We'll probably want to tweak this over time to // decide just how much information to give. let mut names = Vec::new(); - let (trait_ref, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { + let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { ty::ReLateBound(debruijn, match br { ty::BrNamed(_, name) => { names.push(token::get_name(name)); @@ -1181,11 +1177,11 @@ impl<'tcx> UserString<'tcx> for ty::PolyTraitRef<'tcx> { }); let names: Vec<_> = names.iter().map(|s| s.get()).collect(); - let trait_ref_str = trait_ref.value.user_string(tcx); + let value_str = unbound_value.user_string(tcx); if names.len() == 0 { - trait_ref_str + value_str } else { - format!("for<{}> {}", names.connect(","), trait_ref_str) + format!("for<{}> {}", names.connect(","), value_str) } } } @@ -1337,6 +1333,20 @@ impl<'tcx, A:Repr<'tcx>, B:Repr<'tcx>> Repr<'tcx> for (A,B) { impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("Binder({})", self.value.repr(tcx)) + format!("Binder({})", self.0.repr(tcx)) + } +} + +impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap + where K : Hash + Eq + Repr<'tcx>, + V : Repr<'tcx>, + H : Hasher +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("HashMap({})", + self.iter() + .map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx))) + .collect::>() + .connect(", ")) } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 14d36432afaa8..b2c661cc58aa4 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -275,11 +275,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { onceness: ast::Many, store: ty::RegionTraitStore(region_bound, ast::MutMutable), bounds: ty::region_existential_bound(region_bound), - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: input_tys.to_vec(), output: ty::FnConverging(output_ty), variadic: false, - }, + }), abi: abi::Rust, }) } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f1d839e916d56..b947b1746fcab 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -282,10 +282,10 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str) -> ValueRef { let (inputs, output, abi, env) = match fn_ty.sty { ty::ty_bare_fn(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, None) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None) } ty::ty_closure(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx))) } ty::ty_unboxed_closure(closure_did, _, ref substs) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); @@ -293,8 +293,8 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let function_type = unboxed_closure.closure_type.clone(); let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty); let llenvironment_type = type_of_explicit_arg(ccx, self_type); - (function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), - function_type.sig.output.subst(ccx.tcx(), substs), + (function_type.sig.0.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), + function_type.sig.0.output.subst(ccx.tcx(), substs), RustCall, Some(llenvironment_type)) } @@ -1998,7 +1998,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output.unwrap(), + ty::ty_bare_fn(ref bft) => bft.sig.0.output.unwrap(), _ => ccx.sess().bug( format!("trans_enum_variant_constructor: \ unexpected ctor return type {}", @@ -2070,7 +2070,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output, + ty::ty_bare_fn(ref bft) => bft.sig.0.output, _ => ccx.sess().bug( format!("trans_enum_variant_or_tuple_like_struct: \ unexpected ctor return type {}", @@ -2439,7 +2439,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< // at either 1 or 2 depending on whether there's an env slot or not let mut first_arg_offset = if has_env { 2 } else { 1 }; let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; + let ret_ty = fn_sig.0.output; // These have an odd calling convention, so we need to manually // unpack the input ty's @@ -2447,15 +2447,15 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< ty::ty_unboxed_closure(_, _, _) => { assert!(abi == RustCall); - match fn_sig.inputs[0].sty { + match fn_sig.0.inputs[0].sty { ty::ty_tup(ref inputs) => inputs.clone(), _ => ccx.sess().bug("expected tuple'd inputs") } }, ty::ty_bare_fn(_) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; + let mut inputs = vec![fn_sig.0.inputs[0]]; - match fn_sig.inputs[1].sty { + match fn_sig.0.inputs[1].sty { ty::ty_tup(ref t_in) => { inputs.push_all(t_in.as_slice()); inputs @@ -2463,7 +2463,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< _ => ccx.sess().bug("expected tuple'd inputs") } } - _ => fn_sig.inputs.clone() + _ => fn_sig.0.inputs.clone() }; if let ty::FnConverging(ret_ty) = ret_ty { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 7c2f719611632..192b0d6342100 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -280,9 +280,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( match bare_fn_ty.sty { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::Rust, - sig: ty::FnSig { inputs: ref input_tys, - output: output_ty, - variadic: false }}) => + sig: ty::Binder(ty::FnSig { inputs: ref input_tys, + output: output_ty, + variadic: false })}) => { (input_tys, output_ty) } @@ -296,12 +296,12 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let tuple_fn_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::RustCall, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec![bare_fn_ty_ref, tuple_input_ty], output: output_ty, variadic: false - }}); + })}); debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // @@ -421,12 +421,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id); match impl_or_trait_item { ty::MethodTraitItem(method) => { - let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); - let trait_ref = ty::erase_late_bound_regions(tcx, &trait_ref); + let poly_trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); + let trait_ref = ty::erase_late_bound_regions(tcx, &*poly_trait_ref); // Compute the first substitution let first_subst = - ty::make_substs_for_receiver_types(tcx, &trait_ref.value, &*method) + ty::make_substs_for_receiver_types(tcx, &trait_ref, &*method) .erase_regions(); // And compose them @@ -435,7 +435,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( debug!("trans_fn_with_vtables - default method: \ substs = {}, trait_subst = {}, \ first_subst = {}, new_subst = {}", - substs.repr(tcx), trait_ref.substs().repr(tcx), + substs.repr(tcx), trait_ref.substs.repr(tcx), first_subst.repr(tcx), new_substs.repr(tcx)); (true, source_id, new_substs) @@ -657,8 +657,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let mut bcx = callee.bcx; let (abi, ret_ty) = match callee_ty.sty { - ty::ty_bare_fn(ref f) => (f.abi, f.sig.output), - ty::ty_closure(ref f) => (f.abi, f.sig.output), + ty::ty_bare_fn(ref f) => (f.abi, f.sig.0.output), + ty::ty_closure(ref f) => (f.abi, f.sig.0.output), _ => panic!("expected bare rust fn or closure in trans_call_inner") }; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 1811388662c45..af3daf224e326 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -658,9 +658,9 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arena = TypedArena::new(); let empty_param_substs = Substs::trans_empty(); - let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.output, + let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.0.output, &empty_param_substs, None, &arena); - let bcx = init_function(&fcx, true, f.sig.output); + let bcx = init_function(&fcx, true, f.sig.0.output); let args = create_datums_for_fn_args(&fcx, ty::ty_fn_args(closure_ty) @@ -676,7 +676,7 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llargs.extend(args.iter().map(|arg| arg.val)); let retval = Call(bcx, fn_ptr, llargs.as_slice(), None); - match f.sig.output { + match f.sig.0.output { ty::FnConverging(output_type) => { if return_type_is_void(ccx, output_type) || fcx.llretslotptr.get().is_some() { RetVoid(bcx); diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 8fcab0a3144d1..96c39b5796ec4 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -442,7 +442,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str(" fn("); - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -451,12 +451,12 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str(")->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -575,7 +575,7 @@ impl<'tcx> TypeMap<'tcx> { } }; - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -584,13 +584,13 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str("|->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -2787,13 +2787,13 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id: UniqueTypeId, - signature: &ty::FnSig<'tcx>, + signature: &ty::PolyFnSig<'tcx>, span: Span) -> MetadataCreationResult { - let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs.len() + 1); + let mut signature_metadata: Vec = Vec::with_capacity(signature.0.inputs.len() + 1); // return type - signature_metadata.push(match signature.output { + signature_metadata.push(match signature.0.output { ty::FnConverging(ret_ty) => match ret_ty.sty { ty::ty_tup(ref tys) if tys.is_empty() => ptr::null_mut(), _ => type_metadata(cx, ret_ty, span) @@ -2802,7 +2802,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }); // regular arguments - for &argument_type in signature.inputs.iter() { + for &argument_type in signature.0.inputs.iter() { signature_metadata.push(type_metadata(cx, argument_type, span)); } @@ -3781,8 +3781,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3790,8 +3790,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3800,7 +3800,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); @@ -3841,8 +3841,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }; - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3850,8 +3850,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3860,7 +3860,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(param_list_closing_char); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 0bcca6c80ff0d..db44e0ce27197 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -318,8 +318,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions(); let trait_ref = - Rc::new(ty::bind(ty::TraitRef { def_id: principal.def_id(), - substs: substs })); + Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(), + substs: substs })); let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); let box_ty = mk_ty(unadjusted_ty); PointerCast(bcx, diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 615d5467f8464..d072031993050 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -22,7 +22,6 @@ use trans::machine; use trans::type_::Type; use trans::type_of::*; use trans::type_of; -use middle::ty::FnSig; use middle::ty::{mod, Ty}; use middle::subst::{Subst, Substs}; use std::cmp; @@ -41,7 +40,7 @@ use util::ppaux::Repr; struct ForeignTypes<'tcx> { /// Rust signature of the function - fn_sig: ty::FnSig<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, /// Adapter object for handling native ABI rules (trust me, you /// don't want to know) @@ -179,7 +178,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Make sure the calling convention is right for variadic functions // (should've been caught if not in typeck) - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { assert!(cc == llvm::CCallConv); } @@ -386,7 +385,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty)); if llrust_ret_ty == llforeign_ret_ty { - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(result_ty) => { base::store_ty(bcx, llforeign_retval, llretptr, result_ty) } @@ -632,7 +631,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; // Push Rust return pointer, using null if it will be unused. - let rust_uses_outptr = match tys.fn_sig.output { + let rust_uses_outptr = match tys.fn_sig.0.output { ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty), ty::FnDiverging => false }; @@ -665,7 +664,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return_ty={}", ccx.tn().val_to_string(slot), ccx.tn().type_to_string(llrust_ret_ty), - tys.fn_sig.output.repr(tcx)); + tys.fn_sig.0.output.repr(tcx)); llrust_args.push(slot); return_alloca = Some(slot); } @@ -680,8 +679,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Build up the arguments to the call to the rust function. // Careful to adapt for cases where the native convention uses // a pointer and Rust does not or vice versa. - for i in range(0, tys.fn_sig.inputs.len()) { - let rust_ty = tys.fn_sig.inputs[i]; + for i in range(0, tys.fn_sig.0.inputs.len()) { + let rust_ty = tys.fn_sig.0.inputs[i]; let llrust_ty = tys.llsig.llarg_tys[i]; let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty); let llforeign_arg_ty = tys.fn_ty.arg_tys[i]; @@ -826,10 +825,10 @@ pub fn link_name(i: &ast::ForeignItem) -> InternedString { /// because foreign functions just plain ignore modes. They also don't pass aggregate values by /// pointer like we do. fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_sig: &ty::FnSig<'tcx>, arg_tys: &[Ty<'tcx>]) + fn_sig: &ty::PolyFnSig<'tcx>, arg_tys: &[Ty<'tcx>]) -> LlvmSignature { let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect(); - let (llret_ty, ret_def) = match fn_sig.output { + let (llret_ty, ret_def) = match fn_sig.0.output { ty::FnConverging(ret_ty) => (type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), ty::FnDiverging => @@ -853,7 +852,7 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(), _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; - let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice()); + let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice()); let fn_ty = cabi::compute_abi_info(ccx, llsig.llarg_tys.as_slice(), llsig.llret_ty, @@ -913,7 +912,7 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T llargument_tys.push(llarg_ty); } - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty) } else { Type::func(llargument_tys.as_slice(), &llreturn_ty) diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 4575d8a41e52a..dea095ecaf594 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -227,8 +227,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs); let self_ty = match fty.sty { ty::ty_bare_fn(ref f) => { - assert!(f.sig.inputs.len() == 1); - f.sig.inputs[0] + assert!(f.sig.0.inputs.len() == 1); + f.sig.0.inputs[0] } _ => bcx.sess().bug(format!("Expected function type, found {}", bcx.ty_to_string(fty)).as_slice()) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 890652401d7eb..a6f7c849f4d95 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -150,7 +150,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let ret_ty = match callee_ty.sty { - ty::ty_bare_fn(ref f) => f.sig.output, + ty::ty_bare_fn(ref f) => f.sig.0.output, _ => panic!("expected bare_fn in trans_intrinsic_call") }; let foreign_item = tcx.map.expect_foreign_item(node); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index b386df85d627e..a8f7323b4ae03 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -239,8 +239,8 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_assoc, Vec::new())); debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); - let trait_ref = Rc::new(ty::bind(ty::TraitRef { def_id: trait_id, - substs: trait_substs })); + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); let vtbl = fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref); @@ -480,8 +480,8 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => { type_of_rust_fn(ccx, Some(Type::i8p(ccx)), - f.sig.inputs.slice_from(1), - f.sig.output, + f.sig.0.inputs.slice_from(1), + f.sig.0.output, f.abi) } _ => { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index adc919c91bf36..aa6fd7f0b3941 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -146,16 +146,16 @@ pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) ty::ty_closure(ref f) => { type_of_rust_fn(cx, Some(Type::i8p(cx)), - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } ty::ty_bare_fn(ref f) => { if f.abi == abi::Rust || f.abi == abi::RustCall { type_of_rust_fn(cx, None, - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } else { foreign::lltype_for_foreign_fn(cx, fty) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1acd5684d169c..d6438c4062e32 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -535,7 +535,7 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( { let trait_ref = instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); let trait_ref = (*trait_ref).clone(); - Rc::new(ty::bind(trait_ref)) // Ugh. + Rc::new(ty::Binder(trait_ref)) // Ugh. } /// Instantiates the path for the given trait reference, assuming that it's @@ -778,12 +778,12 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - return Ok(ty::bind(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow))); + return Ok(ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow))); } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -993,12 +993,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let result = ty::bind(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow)); + let result = ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow)); trait_ref_to_object_type(this, rscope, path.span, result, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { @@ -1050,7 +1050,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let ty_param_defs = tcx.ty_param_defs.borrow(); let tp_def = &(*ty_param_defs)[did.node]; let assoc_tys = tp_def.bounds.trait_bounds.iter() - .filter_map(|b| find_assoc_ty(this, &b.value, assoc_ident)) + .filter_map(|b| find_assoc_ty(this, &b.0, assoc_ident)) .collect(); (assoc_tys, token::get_name(tp_def.name).to_string()) } @@ -1278,11 +1278,11 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (ty::BareFnTy { unsafety: unsafety, abi: abi, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: self_and_input_tys, output: output_ty, variadic: decl.variadic - } + }), }, explicit_self_category_result) } @@ -1420,9 +1420,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( store: store, bounds: bounds, abi: abi, - sig: ty::FnSig {inputs: input_tys, - output: output_ty, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output_ty, + variadic: decl.variadic}), } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6e5fdbfac9fd3..2ade3040d6cff 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -129,7 +129,7 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // Tuple up the arguments and insert the resulting function type into // the `unboxed_closures` table. - fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]; + fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)]; debug!("unboxed_closure for {} --> sig={} kind={}", expr_def_id.repr(fcx.tcx()), diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 0d07957ba3d97..8ac58736f54b4 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,9 +16,9 @@ use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; -use middle::ty_fold::HigherRankedFoldable; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; @@ -114,7 +114,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final `MethodCallee`. let fty = ty::mk_bare_fn(self.tcx(), ty::BareFnTy { - sig: method_sig, + sig: ty::Binder(method_sig), unsafety: pick.method_ty.fty.unsafety, abi: pick.method_ty.fty.abi.clone(), }); @@ -272,7 +272,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { &trait_def.generics, self.infcx().next_ty_var()); - let trait_ref = Rc::new(ty::bind(ty::TraitRef::new(trait_def_id, substs.clone()))); + let trait_ref = + Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs.clone()))); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) @@ -388,9 +389,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // The binder level here corresponds to the impl. let (all_substs, (method_sig, method_generics)) = self.replace_late_bound_regions_with_fresh_var( - &ty::bind((all_substs, - (pick.method_ty.fty.sig.clone(), - pick.method_ty.generics.clone())))).value; + &ty::Binder((all_substs, + (pick.method_ty.fty.sig.clone(), + pick.method_ty.generics.clone())))); debug!("late-bound lifetimes from impl instantiated, \ all_substs={} method_sig={} method_generics={}", @@ -481,7 +482,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { _ => return, }; - match sig.inputs[0].sty { + match sig.0.inputs[0].sty { ty::ty_rptr(_, ty::mt { ty: _, mutbl: ast::MutMutable, @@ -654,8 +655,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { target_trait_def_id.repr(self.tcx()))[]); } - fn replace_late_bound_regions_with_fresh_var(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn replace_late_bound_regions_with_fresh_var(&self, value: &ty::Binder) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { self.infcx().replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, value).0 diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 14bd0edda1078..451058e5e21a0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -166,7 +166,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Construct a trait-reference `self_ty : Trait` let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty); - let trait_ref = Rc::new(ty::bind(ty::TraitRef::new(trait_def_id, substs))); + let trait_ref = Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs))); // Construct an obligation let obligation = traits::Obligation::misc(span, @@ -204,7 +204,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, &fn_sig).0; let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { - sig: fn_sig, + sig: ty::Binder(fn_sig), unsafety: bare_fn_ty.unsafety, abi: bare_fn_ty.abi.clone(), }); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 452d001fe8aa9..fc1aa59c4deb3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -20,7 +20,7 @@ use middle::subst::Subst; use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::{MethodObject}; -use middle::ty_fold::HigherRankedFoldable; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::ast; @@ -308,8 +308,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let vtable_index = get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); - let xform_self_ty = - this.xform_self_ty(&m, new_trait_ref.substs()); + let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -772,7 +771,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Erase any late-bound regions bound in the impl // which appear in the bounds. - let impl_bounds = self.erase_late_bound_regions(&ty::bind(impl_bounds)).value; + let impl_bounds = self.erase_late_bound_regions(&ty::Binder(impl_bounds)); // Convert the bounds into obligations. let obligations = @@ -874,9 +873,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn xform_self_ty(&self, method: &Rc>, substs: &subst::Substs<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> + { debug!("xform_self_ty(self_ty={}, substs={})", - method.fty.sig.inputs[0].repr(self.tcx()), + method.fty.sig.0.inputs[0].repr(self.tcx()), substs.repr(self.tcx())); // It is possible for type parameters or early-bound lifetimes @@ -909,15 +909,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } // Replace early-bound regions and types. - let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs); + let xform_self_ty = method.fty.sig.0.inputs[0].subst(self.tcx(), substs); // Replace late-bound regions bound in the impl or - // where-clause (2 levels of binding). - let xform_self_ty = - self.erase_late_bound_regions(&ty::bind(ty::bind(xform_self_ty))).value.value; - - // Replace late-bound regions bound in the method (1 level of binding). - self.erase_late_bound_regions(&ty::bind(xform_self_ty)).value + // where-clause (2 levels of binding) and method (1 level of binding). + self.erase_late_bound_regions( + &self.erase_late_bound_regions( + &ty::Binder(ty::Binder(xform_self_ty)))) } fn impl_substs(&self, @@ -955,8 +953,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn erase_late_bound_regions(&self, value: &ty::Binder) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::erase_late_bound_regions(self.tcx(), value) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1e9f7992fb742..18f009fe6c479 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -506,7 +506,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, unsafety: ast::Unsafety, unsafety_id: ast::NodeId, - fn_sig: &ty::FnSig<'tcx>, + fn_sig: &ty::PolyFnSig<'tcx>, decl: &ast::FnDecl, fn_id: ast::NodeId, body: &ast::Block, @@ -723,7 +723,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let body_id = method.pe_body().id; let fty = liberate_late_bound_regions( - ccx.tcx, CodeExtent::from_node_id(body_id), &ty::bind(fty)).value; + ccx.tcx, CodeExtent::from_node_id(body_id), &ty::Binder(fty)); debug!("fty (liberated): {}", fty.repr(ccx.tcx)); check_bare_fn(ccx, @@ -924,7 +924,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let infcx = infer::new_infer_ctxt(tcx); - let trait_to_impl_substs = impl_trait_ref.substs(); + let trait_to_impl_substs = impl_trait_ref.substs; // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected @@ -975,15 +975,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, return; } - if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() { + if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { span_err!(tcx.sess, impl_m_span, E0050, "method `{}` has {} parameter{} \ but the declaration in trait `{}` has {}", token::get_name(trait_m.name), - impl_m.fty.sig.inputs.len(), - if impl_m.fty.sig.inputs.len() == 1 {""} else {"s"}, + impl_m.fty.sig.0.inputs.len(), + if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"}, ty::item_path_str(tcx, trait_m.def_id), - trait_m.fty.sig.inputs.len()); + trait_m.fty.sig.0.inputs.len()); return; } @@ -1085,7 +1085,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // `Bound<&'a T>`, the lifetime `'a` will be late-bound with a // depth of 3 (it is nested within 3 binders: the impl, method, // and trait-ref itself). So when we do the liberation, we have - // two introduce two `ty::bind` scopes, one for the impl and one + // two introduce two `ty::Binder` scopes, one for the impl and one // the method. // // The only late-bounded regions that can possibly appear here are @@ -1103,7 +1103,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, liberate_late_bound_regions( tcx, impl_m_body_scope, - &ty::bind(ty::bind(impl_param_def.bounds.clone()))).value.value); + &ty::Binder(ty::Binder(impl_param_def.bounds.clone()))).0); for (i, (trait_param_bounds, impl_param_bounds)) in trait_bounds.zip(impl_bounds).enumerate() { @@ -1169,7 +1169,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); let impl_fty = liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(impl_fty)).value; + tcx, impl_m_body_scope, &ty::Binder(impl_fty)); let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); @@ -1289,7 +1289,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // impl, and the method. let impl_bounds = ty::liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(ty::bind(impl_bounds))).value.value; + tcx, impl_m_body_scope, &ty::Binder(ty::Binder(impl_bounds))).0; debug!("check_region_bounds_on_impl_method: \ trait_param={} \ @@ -2546,13 +2546,13 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // HACK(eddyb) ignore self in the definition (see above). check_argument_types(fcx, sp, - fty.sig.inputs.slice_from(1), + fty.sig.0.inputs.slice_from(1), callee_expr, args_no_rcvr, autoref_args, - fty.sig.variadic, + fty.sig.0.variadic, tuple_arguments); - fty.sig.output + fty.sig.0.output } _ => { fcx.tcx().sess.span_bug(callee_expr.span, @@ -2966,11 +2966,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - let error_fn_sig = FnSig { + let error_fn_sig = ty::Binder(FnSig { inputs: err_args(args.len()), output: ty::FnConverging(ty::mk_err()), variadic: false - }; + }); let fn_sig = match *fn_sty { ty::ty_bare_fn(ty::BareFnTy {ref sig, ..}) | @@ -5070,7 +5070,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var( span, infer::FnCall, - &ty::bind((polytype.ty, bounds))).0.value; + &ty::Binder((polytype.ty, bounds))).0; debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx())); debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx())); @@ -5686,11 +5686,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi::RustIntrinsic, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: inputs, output: output, variadic: false, - } + }), }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index ad6ba0a1d5571..33c015a9a081c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1181,7 +1181,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Treat overloaded autoderefs as if an AutoRef adjustment // was applied on the base type, as that is always the case. let fn_sig = ty::ty_fn_sig(method.ty); - let self_ty = fn_sig.inputs[0]; + let self_ty = fn_sig.0.inputs[0]; let (m, r) = match self_ty.sty { ty::ty_rptr(r, ref m) => (m.mutbl, r), _ => rcx.tcx().sess.span_bug(deref_expr.span, @@ -1198,7 +1198,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Specialized version of constrain_call. type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(return_type) => { type_must_outlive(rcx, infer::CallReturn(deref_expr.span), return_type, r_deref_expr); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 4a10c698f7d1f..ff91093ab5f72 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -207,12 +207,12 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, } }; let ref sig = method.fty.sig; - for &input_ty in sig.inputs[1..].iter() { + for &input_ty in sig.0.inputs[1..].iter() { if let Some(msg) = check_for_self_ty(input_ty) { msgs.push(msg); } } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { if let Some(msg) = check_for_self_ty(result_type) { msgs.push(msg); } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e11f388b1160d..a90422cd30974 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -170,8 +170,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // liberated. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let self_ty = liberate_late_bound_regions( - fcx.tcx(), item_scope, &ty::bind(self_ty)).value; + let self_ty = liberate_late_bound_regions(fcx.tcx(), item_scope, &ty::Binder(self_ty)); bounds_checker.check_traits_in_ty(self_ty); @@ -186,7 +185,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // There are special rules that apply to drop. if - fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id()) && + fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) && !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") { match self_ty.sty { @@ -200,7 +199,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } - if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id()) { + if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) { // This is checked in coherence. return } @@ -219,10 +218,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { traits::ObligationCause::new( item.span, fcx.body_id, - traits::ItemObligation(trait_ref.def_id())); + traits::ItemObligation(trait_ref.def_id)); // Find the supertrait bounds. This will add `int:Bar`. - let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref); + let poly_trait_ref = ty::Binder(trait_ref); + let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref); for predicate in predicates.into_iter() { fcx.register_predicate(traits::Obligation::new(cause, predicate)); } @@ -264,18 +264,18 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { /// /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated /// to the point where impl `A : Trait` is implemented). - pub fn check_trait_ref(&mut self, trait_ref: &ty::PolyTraitRef<'tcx>) { - let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id()); + pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { + let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id); - let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs()); + let bounds = trait_def.generics.to_bounds(self.tcx(), &trait_ref.substs); self.fcx.add_obligations_for_parameters( traits::ObligationCause::new( self.span, self.fcx.body_id, - traits::ItemObligation(trait_ref.def_id())), + traits::ItemObligation(trait_ref.def_id)), &bounds); - for &ty in trait_ref.substs().types.iter() { + for &ty in trait_ref.substs.types.iter() { self.check_traits_in_ty(ty); } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index e9a3db1b0e6aa..e79eac90508e9 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -477,7 +477,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let self_type = ty::liberate_late_bound_regions(tcx, item_scope, - &ty::bind(self_type)).value; + &ty::Binder(self_type)); debug!("can_type_implement_copy(self_type={})", self_type.repr(tcx)); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8930ae0116052..e4d93123a2691 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1638,8 +1638,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::bind(ty::TraitRef { def_id: local_def(trait_id), - substs: (*substs).clone() })); + Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id), + substs: (*substs).clone() })); let def = ty::TypeParameterDef { space: subst::SelfSpace, @@ -2155,9 +2155,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::BareFnTy { abi: abi, unsafety: ast::Unsafety::Unsafe, - sig: ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output, + variadic: decl.variadic}), }); let pty = Polytype { generics: ty_generics_for_fn_or_method, @@ -2209,16 +2209,16 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( assert!(!ty::type_escapes_depth(required_type, 1)); let required_type_free = ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(required_type)).value; + crate_context.tcx, body_scope, &ty::Binder(required_type)); // The "base type" comes from the impl. It may have late-bound // regions from the impl or the method. - let base_type_free = // liberate impl regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(ty::bind(base_type))).value.value; - let base_type_free = // liberate method regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(base_type_free)).value; + let base_type_free = + ty::liberate_late_bound_regions( // liberate impl regions: + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( // liberate method regions: + crate_context.tcx, body_scope, + &ty::Binder(ty::Binder(base_type)))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d55d642f74651..5fc2466674ebe 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -228,11 +228,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: Vec::new(), output: ty::FnConverging(ty::mk_nil(tcx)), variadic: false - } + }) }); require_same_types(tcx, None, false, main_span, main_t, se_ty, @@ -276,14 +276,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec!( ty::mk_int(), ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) ), output: ty::FnConverging(ty::mk_int()), variadic: false - } + }), }); require_same_types(tcx, None, false, start_span, start_t, se_ty, diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index a70058b977ead..67478e0bfa77e 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -878,13 +878,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); - for &input in sig.inputs.iter() { + for &input in sig.0.inputs.iter() { self.add_constraints_from_ty(input, contra); } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { self.add_constraints_from_ty(result_type, variance); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9509986af4787..661d6ec241ade 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -577,7 +577,7 @@ impl Clean for ty::BuiltinBound { impl<'tcx> Clean for ty::PolyTraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { - self.value.clean(cx) + self.0.clean(cx) } } @@ -919,7 +919,7 @@ impl<'tcx> Clean for ty::FnOutput<'tcx> { } } -impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::FnSig<'tcx>) { +impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; let mut names = if did.node != 0 { @@ -931,10 +931,10 @@ impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::FnSig<'tcx>) { let _ = names.next(); } FnDecl { - output: Return(sig.output.clean(cx)), + output: Return(sig.0.output.clean(cx)), attrs: Vec::new(), inputs: Arguments { - values: sig.inputs.iter().map(|t| { + values: sig.0.inputs.iter().map(|t| { Argument { type_: t.clean(cx), id: 0, @@ -1088,14 +1088,14 @@ impl<'tcx> Clean for ty::Method<'tcx> { ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx), self.fty.sig.clone()), s => { - let sig = ty::FnSig { - inputs: self.fty.sig.inputs[1..].to_vec(), - ..self.fty.sig.clone() - }; + let sig = ty::Binder(ty::FnSig { + inputs: self.fty.sig.0.inputs[1..].to_vec(), + ..self.fty.sig.0.clone() + }); let s = match s { ty::ByValueExplicitSelfCategory => SelfValue, ty::ByReferenceExplicitSelfCategory(..) => { - match self.fty.sig.inputs[0].sty { + match self.fty.sig.0.inputs[0].sty { ty::ty_rptr(r, mt) => { SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx)) } @@ -1103,7 +1103,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { } } ty::ByBoxExplicitSelfCategory => { - SelfExplicit(self.fty.sig.inputs[0].clean(cx)) + SelfExplicit(self.fty.sig.0.inputs[0].clean(cx)) } ty::StaticExplicitSelfCategory => unreachable!(), }; @@ -1398,7 +1398,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) | ty::ty_trait(box ty::TyTrait { - principal: ty::Binder { value: ty::TraitRef { def_id: did, ref substs } }, + principal: ty::Binder(ty::TraitRef { def_id: did, ref substs }), .. }) => { let fqn = csearch::get_item_path(cx.tcx(), did); From 4f34524fcbd9672e2fd6bb27e657da2c26051fdf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 12 Dec 2014 14:55:07 -0500 Subject: [PATCH 14/24] Move `leak_check` into its own method, and ensure that all higher-ranked code is in `higher_ranked.rs`. --- .../middle/infer/higher_ranked/mod.rs | 53 ++++++++++++++++--- src/librustc/middle/infer/mod.rs | 23 ++++---- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index dcc365fad18ee..ca4a6b28c2a1c 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}; +use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; use super::combine::{Combine, Combineable}; use middle::ty::{mod, Binder}; @@ -81,7 +81,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - match leak_check(self.infcx(), &skol_map, snapshot) { + match self.infcx().leak_check(&skol_map, snapshot) { Ok(()) => { } Err((skol_br, tainted_region)) => { if self.a_is_expected() { @@ -455,11 +455,47 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { } } -fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, - skol_map: &FnvHashMap, - snapshot: &CombinedSnapshot) - -> Result<(),(ty::BoundRegion,ty::Region)> +pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + binder: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> { + /*! + * Replace all regions bound by `binder` with skolemized regions and + * return a map indicating which bound-region was replaced with what + * skolemized region. This is the first step of checking subtyping + * when higher-ranked things are involved. See `doc.rs` for more details. + */ + + let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br, _| { + infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); + + debug!("skolemize_bound_regions(binder={}, result={}, map={})", + binder.repr(infcx.tcx), + result.repr(infcx.tcx), + map.repr(infcx.tcx)); + + (result, map) +} + +pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> +{ + /*! + * Searches the region constriants created since `snapshot` was started + * and checks to determine whether any of the skolemized regions created + * in `skol_map` would "escape" -- meaning that they are related to + * other regions in some way. If so, the higher-ranked subtyping doesn't + * hold. See `doc.rs` for more details. + */ + + debug!("leak_check: skol_map={}", + skol_map.repr(infcx.tcx)); + let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); for (&skol_br, &skol) in skol_map.iter() { let tainted = infcx.tainted_regions(snapshot, skol); @@ -475,6 +511,11 @@ fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, } }; + debug!("{} (which replaced {}) is tainted by {}", + skol.repr(infcx.tcx), + skol_br.repr(infcx.tcx), + tainted_region.repr(infcx.tcx)); + // A is not as polymorphic as B: return Err((skol_br, tainted_region)); } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index edd5c8b854e1f..0dfae4b882b7f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -52,7 +52,7 @@ pub mod doc; pub mod equate; pub mod error_reporting; pub mod glb; -pub mod higher_ranked; +mod higher_ranked; pub mod lattice; pub mod lub; pub mod region_inference; @@ -90,7 +90,7 @@ pub struct InferCtxt<'a, 'tcx: 'a> { RegionVarBindings<'a, 'tcx>, } -/// A map returned by `skolemize_bound_regions()` indicating the skolemized +/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. pub type SkolemizationMap = FnvHashMap; @@ -709,16 +709,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> (T, SkolemizationMap) where T : TypeFoldable<'tcx> + Repr<'tcx> { - let (result, map) = replace_late_bound_regions(self.tcx, value, |br, _| { - self.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) - }); + /*! See `higher_ranked::skolemize_late_bound_regions` */ - debug!("skolemize_bound_regions(value={}, result={}, map={})", - value.repr(self.tcx), - result.repr(self.tcx), - map.repr(self.tcx)); + higher_ranked::skolemize_late_bound_regions(self, value, snapshot) + } + + pub fn leak_check(&self, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> + { + /*! See `higher_ranked::leak_check` */ - (result, map) + higher_ranked::leak_check(self, skol_map, snapshot) } pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { From c2ca1a4b622baa8394ab19e76bef75afe680ad18 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 13 Dec 2014 05:34:34 -0500 Subject: [PATCH 15/24] Make all predicates higher-ranked, not just trait references. --- src/librustc/metadata/tydecode.rs | 16 +- src/librustc/metadata/tyencode.rs | 6 +- .../middle/infer/higher_ranked/mod.rs | 2 +- src/librustc/middle/infer/mod.rs | 33 +++- src/librustc/middle/traits/fulfill.rs | 47 ++++-- src/librustc/middle/traits/select.rs | 13 +- src/librustc/middle/ty.rs | 151 ++++++++++++++---- src/librustc/middle/ty_fold.rs | 32 ++-- src/librustc/util/ppaux.rs | 53 ++++++ src/librustc_typeck/check/vtable.rs | 82 ++++------ src/librustc_typeck/collect.rs | 15 +- src/libsyntax/visit.rs | 19 ++- 12 files changed, 336 insertions(+), 133 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index f3d700f013d81..f2a41c48d1203 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -21,7 +21,7 @@ pub use self::DefIdSource::*; use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, Ty}; use std::rc::Rc; use std::str; @@ -669,13 +669,13 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => ty::Predicate::Trait(Rc::new(ty::Binder(parse_trait_ref(st, conv)))), - 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), - parse_ty(st, |x,y| conv(x,y))), - 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), - 'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), + 't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(), + 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)), + parse_ty(st, |x,y| conv(x,y)))).as_predicate(), + 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), + 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index c6218e6fe9478..5d7d85d4679d7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -427,17 +427,17 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, mywrite!(w, "t"); enc_trait_ref(w, cx, &trait_ref.0); } - ty::Predicate::Equate(a, b) => { + ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { mywrite!(w, "e"); enc_ty(w, cx, a); enc_ty(w, cx, b); } - ty::Predicate::RegionOutlives(a, b) => { + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "r"); enc_region(w, cx, a); enc_region(w, cx, b); } - ty::Predicate::TypeOutlives(a, b) => { + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "o"); enc_ty(w, cx, a); enc_region(w, cx, b); diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index ca4a6b28c2a1c..3a84890de4f4b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -81,7 +81,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - match self.infcx().leak_check(&skol_map, snapshot) { + match leak_check(self.infcx(), &skol_map, snapshot) { Ok(()) => { } Err((skol_br, tainted_region)) => { if self.a_is_expected() { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 0dfae4b882b7f..29021c0cca6b9 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -717,11 +717,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn leak_check(&self, skol_map: &SkolemizationMap, snapshot: &CombinedSnapshot) - -> Result<(),(ty::BoundRegion,ty::Region)> + -> ures<'tcx> { /*! See `higher_ranked::leak_check` */ - higher_ranked::leak_check(self, skol_map, snapshot) + match higher_ranked::leak_check(self, skol_map, snapshot) { + Ok(()) => Ok(()), + Err((br, r)) => Err(ty::terr_regions_insufficiently_polymorphic(br, r)) + } + } + + pub fn equality_predicate(&self, + span: Span, + predicate: &ty::PolyEquatePredicate<'tcx>) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::EquatePredicate(a, b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = EquatePredicate(span); + let () = try!(mk_eqty(self, false, origin, a, b)); + self.leak_check(&skol_map, snapshot) + }) + } + + pub fn region_outlives_predicate(&self, + span: Span, + predicate: &ty::PolyRegionOutlivesPredicate) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::OutlivesPredicate(r_a, r_b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = RelateRegionParamBound(span); + let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b` + self.leak_check(&skol_map, snapshot) + }) } pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 8433313cb3718..32d9056f7b778 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::infer::InferCtxt; use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; use std::collections::HashSet; use std::collections::hash_map::{Occupied, Vacant}; use std::default::Default; @@ -329,30 +329,50 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } - ty::Predicate::Equate(a, b) => { - let origin = infer::EquatePredicate(predicate.cause.span); - match infer::mk_eqty(selcx.infcx(), false, origin, a, b) { - Ok(()) => { - true - } + ty::Predicate::Equate(ref binder) => { + match selcx.infcx().equality_predicate(predicate.cause.span, binder) { + Ok(()) => { } Err(_) => { errors.push( FulfillmentError::new( predicate.clone(), CodeSelectionError(Unimplemented))); - true } } + true } - ty::Predicate::RegionOutlives(r_a, r_b) => { - let origin = infer::RelateRegionParamBound(predicate.cause.span); - let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b` + ty::Predicate::RegionOutlives(ref binder) => { + match selcx.infcx().region_outlives_predicate(predicate.cause.span, binder) { + Ok(()) => { } + Err(_) => { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } + } + true } - ty::Predicate::TypeOutlives(t_a, r_b) => { - register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + ty::Predicate::TypeOutlives(ref binder) => { + // For now, we just check that there are no higher-ranked + // regions. If there are, we will call this obligation an + // error. Eventually we should be able to support some + // cases here, I imagine (e.g., `for<'a> &'a int : 'a`). + // + // TODO This is overly conservative, but good enough for + // now. + if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } else { + let ty::OutlivesPredicate(t_a, r_b) = binder.0; + register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + } true } } @@ -385,3 +405,4 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, } } + diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index e0a40901ee851..0bda04237b631 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -28,7 +28,7 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::{mod, Ty, RegionEscape}; +use middle::ty::{mod, AsPredicate, RegionEscape, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -288,8 +288,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_obligation_recursively(previous_stack, &obligation) } - ty::Predicate::Equate(a, b) => { - match infer::can_mk_eqty(self.infcx, a, b) { + ty::Predicate::Equate(ref p) => { + let result = self.infcx.probe(|| { + self.infcx.equality_predicate(obligation.cause.span, p) + }); + match result { Ok(()) => EvaluatedToOk, Err(_) => EvaluatedToErr(Unimplemented), } @@ -1447,8 +1450,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation { cause: obligation.cause, recursion_depth: obligation.recursion_depth+1, - trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(), - ty::ReStatic) + trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(), + ty::ReStatic)).as_predicate(), }); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a24992e89e35d..91247d8b73e41 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1689,23 +1689,60 @@ pub enum Predicate<'tcx> { Trait(Rc>), /// where `T1 == T2`. - Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>), + Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(/* 'a */ Region, /* 'b */ Region), + RegionOutlives(PolyRegionOutlivesPredicate), /// where T : 'a - TypeOutlives(Ty<'tcx>, Region), + TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` +pub type PolyEquatePredicate<'tcx> = ty::Binder>; + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct OutlivesPredicate(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate = ty::Binder>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; + +pub trait AsPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> AsPredicate<'tcx> for Rc> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Trait(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Equate(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::RegionOutlives(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::TypeOutlives(self.clone()) + } } impl<'tcx> Predicate<'tcx> { pub fn has_escaping_regions(&self) -> bool { match *self { Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), - Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) || - ty::type_has_escaping_regions(b)), - Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0), - Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0), + Predicate::Equate(ref p) => p.has_escaping_regions(), + Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), + Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), } } @@ -5208,17 +5245,20 @@ pub fn predicates<'tcx>( for builtin_bound in bounds.builtin_bounds.iter() { match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { - Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); } + Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } Err(ErrorReported) => { } } } for ®ion_bound in bounds.region_bounds.iter() { - vec.push(Predicate::TypeOutlives(param_ty, region_bound)); + // account for the binder being introduced below; no need to shift `param_ty` + // because, at present at least, it can only refer to early-bound regions + let region_bound = ty_fold::shift_region(region_bound, 1); + vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate()); } for bound_trait_ref in bounds.trait_bounds.iter() { - vec.push(Predicate::Trait((*bound_trait_ref).clone())); + vec.push(bound_trait_ref.as_predicate()); } vec @@ -5595,19 +5635,27 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::required_region_bounds(tcx, open_ty, predicates) } -/// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes -/// which the type must outlive. +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice (see `object_region_bounds` above). /// -/// Requires that trait definitions have been processed. +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - param_ty: Ty<'tcx>, + erased_self_ty: Ty<'tcx>, predicates: Vec>) -> Vec { - debug!("required_region_bounds(param_ty={}, predicates={})", - param_ty.repr(tcx), + debug!("required_region_bounds(erased_self_ty={}, predicates={})", + erased_self_ty.repr(tcx), predicates.repr(tcx)); + assert!(!erased_self_ty.has_escaping_regions()); + traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { match predicate { @@ -5616,9 +5664,22 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::Predicate::RegionOutlives(..) => { None } - ty::Predicate::TypeOutlives(t, r) => { - if t == param_ty { - Some(r) + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + if r.has_escaping_regions() { + Some(ty::ReStatic) + } else { + Some(r) + } } else { None } @@ -6100,16 +6161,20 @@ pub fn construct_parameter_environment<'tcx>( Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { // No region bounds here } - Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => { - // Record that `'a:'b`. Or, put another way, `'b <= 'a`. - tcx.region_maps.relate_free_regions(fr_b, fr_a); - } - Predicate::RegionOutlives(r_a, r_b) => { - // All named regions are instantiated with free regions. - tcx.sess.bug( - format!("record_region_bounds: non free region: {} / {}", - r_a.repr(tcx), - r_b.repr(tcx)).as_slice()); + Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { + match (r_a, r_b) { + (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { + // Record that `'a:'b`. Or, put another way, `'b <= 'a`. + tcx.region_maps.relate_free_regions(fr_b, fr_a); + } + _ => { + // All named regions are instantiated with free regions. + tcx.sess.bug( + format!("record_region_bounds: non free region: {} / {}", + r_a.repr(tcx), + r_b.repr(tcx)).as_slice()); + } + } } } } @@ -6313,6 +6378,16 @@ pub fn liberate_late_bound_regions<'tcx, T>( |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0 } +pub fn count_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + value: &Binder) + -> uint + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + let (_, skol_map) = replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic); + skol_map.len() +} + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions<'tcx, T>( @@ -6454,9 +6529,9 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { Predicate::Trait(ref a) => a.repr(tcx), - Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)), - Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), - Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), + Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)), + Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), + Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), } } } @@ -6586,9 +6661,15 @@ impl<'tcx,T:RegionEscape> RegionEscape for Binder { } } -impl Binder { - pub fn has_bound_regions(&self) -> bool { - self.0.has_regions_escaping_depth(0) +impl<'tcx> RegionEscape for EquatePredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) + } +} + +impl RegionEscape for OutlivesPredicate { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 6d6dc1d426ad6..496a0badd8236 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -409,15 +409,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Equate(ref a, ref b) => - ty::Predicate::Equate(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::RegionOutlives(ref a, ref b) => - ty::Predicate::RegionOutlives(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::TypeOutlives(ref a, ref b) => - ty::Predicate::TypeOutlives(a.fold_with(folder), - b.fold_with(folder)), + ty::Predicate::Equate(ref binder) => + ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::RegionOutlives(ref binder) => + ty::Predicate::RegionOutlives(binder.fold_with(folder)), + ty::Predicate::TypeOutlives(ref binder) => + ty::Predicate::TypeOutlives(binder.fold_with(folder)), } } } @@ -501,6 +498,23 @@ impl<'tcx> TypeFoldable<'tcx> for traits::VtableParamData<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> { + ty::EquatePredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + +impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn fold_with>(&self, folder: &mut F) -> ty::OutlivesPredicate { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 134006bef0b75..b0124977c9f1b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1350,3 +1350,56 @@ impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap .connect(", ")) } } + +impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate + where T : Repr<'tcx> + TypeFoldable<'tcx>, + U : Repr<'tcx> + TypeFoldable<'tcx>, +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("OutlivesPredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate + where T : UserString<'tcx> + TypeFoldable<'tcx>, + U : UserString<'tcx> + TypeFoldable<'tcx>, +{ + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} : {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("EquatePredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} == {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + match *self { + ty::Predicate::Trait(ref trait_ref) => { + format!("{} : {}", + trait_ref.self_ty().user_string(tcx), + trait_ref.user_string(tcx)) + } + ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx), + ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx), + ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx), + } + } +} diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index ff91093ab5f72..4db795a1fda55 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -315,36 +315,13 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match *error { Overflow => { // We could track the stack here more precisely if we wanted, I imagine. - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(fcx.tcx()), - trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(&a); - let b = fcx.infcx().resolve_type_vars_if_possible(&b); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow checking whether the types `{}` and `{}` are equal", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!("overflow evaluating lifetime predicate").as_slice()); - } - } + let predicate = + fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the requirement `{}`", + predicate.user_string(fcx.tcx())).as_slice()); let current_limit = fcx.tcx().sess.recursion_limit.get(); let suggested_limit = current_limit * 2; @@ -359,8 +336,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Unimplemented => { match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); + let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); if !ty::type_is_error(trait_ref.self_ty()) { fcx.tcx().sess.span_err( obligation.cause.span, @@ -368,34 +344,44 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "the trait `{}` is not implemented for the type `{}`", trait_ref.user_string(fcx.tcx()), trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); } } - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(&a); - let b = fcx.infcx().resolve_type_vars_if_possible(&b); - let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err(); + ty::Predicate::Equate(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().equality_predicate(obligation.cause.span, + &predicate).unwrap_err(); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); + } + + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().region_outlives_predicate(obligation.cause.span, + &predicate).unwrap_err(); fcx.tcx().sess.span_err( obligation.cause.span, format!( - "mismatched types: the types `{}` and `{}` are not equal ({})", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx()), + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); } - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - // these kinds of predicates turn into - // constraints, and hence errors show up in region - // inference. - fcx.tcx().sess.span_bug( + ty::Predicate::TypeOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + fcx.tcx().sess.span_err( obligation.cause.span, - format!("region predicate error {}", - obligation.repr(fcx.tcx())).as_slice()); + format!( + "the requirement `{}` is not satisfied", + predicate.user_string(fcx.tcx())).as_slice()); } } + + note_obligation_cause(fcx, obligation); } OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e4d93123a2691..485f0ca84304d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,10 +42,9 @@ use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; -use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{Polytype}; -use middle::ty::{mod, Ty}; -use middle::ty_fold::TypeFolder; +use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use middle::ty::{mod, Ty, Polytype}; +use middle::ty_fold::{mod, TypeFolder}; use middle::infer; use rscope::*; use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; @@ -1920,8 +1919,12 @@ fn ty_generics<'tcx,AC>(this: &AC, for region_param_def in result.regions.get_slice(space).iter() { let region = region_param_def.to_early_bound_region(); for &bound_region in region_param_def.bounds.iter() { - result.predicates.push(space, ty::Predicate::RegionOutlives(region, - bound_region)); + // account for new binder introduced in the predicate below; no need + // to shift `region` because it is never a late-bound region + let bound_region = ty_fold::shift_region(bound_region, 1); + result.predicates.push( + space, + ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate()); } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 95d7906b44354..5a1a186c74c4e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -105,8 +105,11 @@ pub trait Visitor<'v> { None => () } } + fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) { + walk_lifetime_bound(self, lifetime) + } fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { - self.visit_name(lifetime.span, lifetime.name) + walk_lifetime_ref(self, lifetime) } fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) @@ -214,10 +217,20 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); for bound in lifetime_def.bounds.iter() { - visitor.visit_lifetime_ref(bound); + visitor.visit_lifetime_bound(bound); } } +pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_lifetime_ref(lifetime_ref) +} + +pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_name(lifetime_ref.span, lifetime_ref.name) +} + pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { @@ -550,7 +563,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_poly_trait_ref(typ); } RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime_ref(lifetime); + visitor.visit_lifetime_bound(lifetime); } } } From f45c0ef51e342c552021a80ddd343b0c7175111e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 14 Dec 2014 07:17:23 -0500 Subject: [PATCH 16/24] Implement "perfect forwarding" for HR impls (#19730). --- src/librustc/lint/builtin.rs | 4 +- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 4 +- src/librustc/middle/astencode.rs | 8 +- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/infer/error_reporting.rs | 13 +- .../middle/infer/higher_ranked/mod.rs | 102 +++++- src/librustc/middle/infer/mod.rs | 47 ++- src/librustc/middle/privacy.rs | 10 +- src/librustc/middle/resolve_lifetime.rs | 9 +- src/librustc/middle/traits/coherence.rs | 15 +- src/librustc/middle/traits/fulfill.rs | 5 +- src/librustc/middle/traits/select.rs | 292 ++++++++++-------- src/librustc/middle/ty.rs | 57 ++-- src/librustc/middle/ty_fold.rs | 33 +- src/librustc_trans/save/mod.rs | 4 +- src/librustc_trans/trans/callee.rs | 5 +- src/librustc_trans/trans/meth.rs | 6 +- src/librustc_typeck/astconv.rs | 19 +- src/librustc_typeck/check/method/confirm.rs | 55 ++-- src/librustc_typeck/check/method/mod.rs | 16 +- src/librustc_typeck/check/method/probe.rs | 32 +- src/librustc_typeck/check/mod.rs | 62 +--- src/librustc_typeck/check/wf.rs | 5 +- src/librustc_typeck/coherence/mod.rs | 24 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustc_typeck/collect.rs | 98 +++--- src/librustdoc/clean/inline.rs | 2 +- .../compile-fail/hrtb-conflate-regions.rs | 40 +++ src/test/compile-fail/hrtb-just-for-static.rs | 37 +++ .../compile-fail/hrtb-perfect-forwarding.rs | 66 ++++ src/test/compile-fail/hrtb-type-outlives.rs | 59 ++++ src/test/compile-fail/issue-14366.rs | 1 - .../kindck-inherited-copy-bound.rs | 7 +- .../unboxed-closures-unsafe-extern-fn.rs | 9 +- .../unboxed-closures-wrong-abi.rs | 10 +- ...boxed-closures-wrong-arg-type-extern-fn.rs | 9 +- 38 files changed, 759 insertions(+), 416 deletions(-) create mode 100644 src/test/compile-fail/hrtb-conflate-regions.rs create mode 100644 src/test/compile-fail/hrtb-just-for-static.rs create mode 100644 src/test/compile-fail/hrtb-perfect-forwarding.rs create mode 100644 src/test/compile-fail/hrtb-type-outlives.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ca8eee847d3f9..f6fd9f60e5c3f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1784,9 +1784,7 @@ impl LintPass for Stability { method_num: index, .. }) => { - ty::trait_item(cx.tcx, - trait_ref.def_id(), - index).def_id() + ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id() } } } diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 1a1c810b27814..4cbb1babf9a2c 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -262,7 +262,7 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId, // if there is one. pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) - -> Option>> { + -> Option>> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_impl_trait(&*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 0625c50d6721f..7f1df80da3c8f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -425,11 +425,11 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec { pub fn get_impl_trait<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> Option>> + -> Option>> { let item_doc = lookup_item(id, cdata.data()); reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { - Rc::new(ty::Binder(doc_trait_ref(tp, tcx, cdata))) + Rc::new(doc_trait_ref(tp, tcx, cdata)) }) } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 0021533a2bbe6..69fbd59fd9241 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTypeParam", 2, 1, |this| { this.emit_struct("MethodParam", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &p.trait_ref.0)) + Ok(this.emit_trait_ref(ecx, &*p.trait_ref)) })); try!(this.emit_struct_field("method_num", 0, |this| { this.emit_uint(p.method_num) @@ -901,7 +901,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("MethodTraitObject", 3, 1, |this| { this.emit_struct("MethodObject", 2, |this| { try!(this.emit_struct_field("trait_ref", 0, |this| { - Ok(this.emit_trait_ref(ecx, &o.trait_ref.0)) + Ok(this.emit_trait_ref(ecx, &*o.trait_ref)) })); try!(this.emit_struct_field("object_trait_id", 0, |this| { Ok(this.emit_def_id(o.object_trait_id)) @@ -1457,7 +1457,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::MethodParam { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_poly_trait_ref(dcx)) + Ok(this.read_trait_ref(dcx)) }).unwrap() }, method_num: { @@ -1475,7 +1475,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { ty::MethodObject { trait_ref: { this.read_struct_field("trait_ref", 0, |this| { - Ok(this.read_poly_trait_ref(dcx)) + Ok(this.read_trait_ref(dcx)) }).unwrap() }, object_trait_id: { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 46c4de5c35ed0..939775e750713 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { .. }) => { let trait_item = ty::trait_item(self.tcx, - trait_ref.def_id(), + trait_ref.def_id, index); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8b0df4e69cd8e..901944cd0168e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -265,7 +265,7 @@ impl OverloadedCallType { } Some(ref trait_ref) => (*trait_ref).clone(), }; - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id()) + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) } fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId) @@ -292,7 +292,7 @@ impl OverloadedCallType { } MethodTypeParam(MethodParam { ref trait_ref, .. }) | MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - OverloadedCallType::from_trait_id(tcx, trait_ref.def_id()) + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) } } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index d1253e0b6976b..b4c1c0b396b64 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) } } @@ -1647,6 +1648,16 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { } } +impl<'tcx> Resolvable<'tcx> for Rc> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) + -> Rc> { + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) + } + fn contains_error(&self) -> bool { + ty::trait_ref_contains_error(&**self) + } +} + impl<'tcx> Resolvable<'tcx> for Rc> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc> { diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 3a84890de4f4b..ab0f98ec74a7f 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -219,7 +219,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C self.infcx().resolve_type_vars_if_possible(&result0); debug!("glb result0 = {}", result0.repr(self.tcx())); - // Generalize the regions appearing in fn_ty0 if possible + // 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 result1 = @@ -358,7 +358,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, where T : Combineable<'tcx>, F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { - unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| { + unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables @@ -414,11 +414,11 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { * * The reason is that when we walk through the subtyping * algorith, we begin by replacing `'a` with a skolemized - * variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This - * can be made true by unifying `_#0t` with `&'0 int`. In the + * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This + * can be made true by unifying `_#0t` with `&'1 int`. In the * process, we create a fresh variable for the skolemized - * region, `'$0`, and hence we have that `_#0t == &'$0 - * int`. However, because `'$0` was created during the sub + * region, `'$2`, and hence we have that `_#0t == &'$2 + * int`. However, because `'$2` was created during the sub * computation, if we're not careful we will erroneously * assume it is one of the transient region variables * representing a lub/glb internally. Not good. @@ -522,3 +522,93 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, } Ok(()) } + +/// This code converts from skolemized regions back to late-bound +/// regions. It works by replacing each region in the taint set of a +/// skolemized region with a bound-region. The bound region will be bound +/// by the outer-most binder in `value`; the caller must ensure that there is +/// such a binder and it is the right place. +/// +/// This routine is only intended to be used when the leak-check has +/// passed; currently, it's used in the trait matching code to create +/// a set of nested obligations frmo an impl that matches against +/// something higher-ranked. More details can be found in +/// `middle::traits::doc.rs`. +/// +/// As a brief example, consider the obligation `for<'a> Fn(&'a int) +/// -> &'a int`, and the impl: +/// +/// impl Fn for SomethingOrOther +/// where A : Clone +/// { ... } +/// +/// Here we will have replaced `'a` with a skolemized region +/// `'0`. This means that our substitution will be `{A=>&'0 +/// int, R=>&'0 int}`. +/// +/// When we apply the substitution to the bounds, we will wind up with +/// `&'0 int : Clone` as a predicate. As a last step, we then go and +/// replace `'0` with a late-bound region `'a`. The depth is matched +/// to the depth of the predicate, in this case 1, so that the final +/// predicate is `for<'a> &'a int : Clone`. +pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok()); + + debug!("plug_leaks(skol_map={}, value={})", + skol_map.repr(infcx.tcx), + value.repr(infcx.tcx)); + + // Compute a mapping from the "taint set" of each skolemized + // region back to the `ty::BoundRegion` that it originally + // represented. Because `leak_check` passed, we know that that + // these taint sets are mutually disjoint. + let inv_skol_map: FnvHashMap = + skol_map + .into_iter() + .flat_map(|(skol_br, skol)| { + infcx.tainted_regions(snapshot, skol) + .into_iter() + .map(move |tainted_region| (tainted_region, skol_br)) + }) + .collect(); + + debug!("plug_leaks: inv_skol_map={}", + inv_skol_map.repr(infcx.tcx)); + + // Remove any instantiated type variables from `value`; those can hide + // references to regions from the `fold_regions` code below. + let value = infcx.resolve_type_vars_if_possible(value); + + // Map any skolemization byproducts back to a late-bound + // region. Put that late-bound region at whatever the outermost + // binder is that we encountered in `value`. The caller is + // responsible for ensuring that (a) `value` contains at least one + // binder and (b) that binder is the one we want to use. + let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| { + match inv_skol_map.get(&r) { + None => r, + Some(br) => { + // It is the responsibility of the caller to ensure + // that each skolemized region appears within a + // binder. In practice, this routine is only used by + // trait checking, and all of the skolemized regions + // appear inside predicates, which always have + // binders, so this assert is satisfied. + assert!(current_depth > 1); + + ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + } + } + }); + + debug!("plug_leaks: result={}", + result.repr(infcx.tcx)); + + result +} diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 29021c0cca6b9..f419f050cf594 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -137,7 +137,8 @@ impl Copy for TypeOrigin {} #[deriving(Clone, Show)] pub enum ValuePairs<'tcx> { Types(ty::expected_found>), - TraitRefs(ty::expected_found>>), + TraitRefs(ty::expected_found>>), + PolyTraitRefs(ty::expected_found>>), } /// The trace designates the path through inference that we took to @@ -349,7 +350,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -362,7 +363,7 @@ pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -634,11 +635,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where - F: FnOnce() -> R, + F: FnOnce(&CombinedSnapshot) -> R, { debug!("probe()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); self.rollback_to(snapshot); r } @@ -683,6 +684,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + pub fn sub_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc>, + b: Rc>) + -> ures<'tcx> + { + debug!("sub_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + self.commit_if_ok(|| { + let trace = TypeTrace { + 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() + }) + } + pub fn sub_poly_trait_refs(&self, a_is_expected: bool, origin: TypeOrigin, @@ -690,14 +710,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { b: Rc>) -> ures<'tcx> { - debug!("sub_trait_refs({} <: {})", + debug!("sub_poly_trait_refs({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); self.commit_if_ok(|| { let trace = TypeTrace { origin: origin, - values: TraitRefs(expected_found(a_is_expected, - a.clone(), b.clone())) + values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures() }) @@ -727,6 +746,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + pub fn plug_leaks(&self, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + higher_ranked::plug_leaks(self, skol_map, snapshot, value) + } + pub fn equality_predicate(&self, span: Span, predicate: &ty::PolyEquatePredicate<'tcx>) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 67e9d2fee58f4..8cce1321d728b 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -257,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { }; let tr = ty::impl_trait_ref(self.tcx, local_def(item.id)); let public_trait = tr.clone().map_or(false, |tr| { - !is_local(tr.def_id()) || - self.exported_items.contains(&tr.def_id().node) + !is_local(tr.def_id) || + self.exported_items.contains(&tr.def_id.node) }); if public_ty || public_trait { @@ -407,7 +407,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.def_id()) + self.def_privacy(t.def_id) } None => { debug!("privacy - found a method {}", @@ -432,7 +432,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match ty::impl_trait_ref(self.tcx, id) { Some(t) => { debug!("privacy - impl of trait {}", id); - self.def_privacy(t.def_id()) + self.def_privacy(t.def_id) } None => { debug!("privacy - found a typedef {}", @@ -811,7 +811,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // is whether the trait itself is accessible or not. MethodTypeParam(MethodParam { ref trait_ref, .. }) | MethodTraitObject(MethodObject { ref trait_ref, .. }) => { - self.report_error(self.ensure_public(span, trait_ref.def_id(), + self.report_error(self.ensure_public(span, trait_ref.def_id, None, "source trait")); } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1923142be9e3f..33701905aa110 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -108,7 +108,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(_, ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _, _) | + ast::ItemImpl(_, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE); @@ -117,12 +118,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { visit::walk_item(this, item); }); } - ast::ItemImpl(_, ref generics, _, _, _) => { - // Impls have both early- and late-bound lifetimes. - this.visit_early_late(subst::TypeSpace, generics, |this| { - visit::walk_item(this, item); - }) - } } }); } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 3b759b042f2ac..9804f6d222afd 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,7 @@ use super::util; use middle::subst; use middle::subst::Subst; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; +use middle::infer::InferCtxt; use std::rc::Rc; use syntax::ast; use syntax::codemap::DUMMY_SP; @@ -38,12 +38,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, let impl1_substs = util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); let impl1_trait_ref = - ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap() - .subst(infcx.tcx, &impl1_substs); - let impl1_trait_ref = - infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP, - infer::FnCall, - &*impl1_trait_ref).0; + (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs); // Determine whether `impl2` can provide an implementation for those // same types. @@ -67,15 +62,15 @@ pub fn impl_is_local(tcx: &ty::ctxt, debug!("trait_ref={}", trait_ref.repr(tcx)); // If the trait is local to the crate, ok. - if trait_ref.def_id().krate == ast::LOCAL_CRATE { + if trait_ref.def_id.krate == ast::LOCAL_CRATE { debug!("trait {} is local to current crate", - trait_ref.def_id().repr(tcx)); + trait_ref.def_id.repr(tcx)); return true; } // Otherwise, at least one of the input types must be local to the // crate. - trait_ref.0.input_types().iter().any(|&t| ty_is_local(tcx, t)) + trait_ref.input_types().iter().any(|&t| ty_is_local(tcx, t)) } pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 32d9056f7b778..213d97b4b344a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -360,10 +360,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, // For now, we just check that there are no higher-ranked // regions. If there are, we will call this obligation an // error. Eventually we should be able to support some - // cases here, I imagine (e.g., `for<'a> &'a int : 'a`). - // - // TODO This is overly conservative, but good enough for - // now. + // cases here, I imagine (e.g., `for<'a> int : 'a`). if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 { errors.push( FulfillmentError::new( diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0bda04237b631..6c7ae666ae06c 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -289,7 +289,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Predicate::Equate(ref p) => { - let result = self.infcx.probe(|| { + let result = self.infcx.probe(|_| { self.infcx.equality_predicate(obligation.cause.span, p) }); match result { @@ -410,13 +410,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id.repr(self.tcx()), obligation.repr(self.tcx())); - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(substs) => { let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, - obligation.recursion_depth + 1); + obligation.recursion_depth + 1, + skol_map, + snapshot); self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() } Err(()) => { @@ -711,8 +716,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let matching_bounds = all_bounds.filter( |bound| self.infcx.probe( - || self.match_trait_refs(obligation, - (*bound).clone())).is_ok()); + |_| self.match_where_clause(obligation, bound.clone())).is_ok()); let param_candidates = matching_bounds.map( @@ -819,8 +823,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { let all_impls = self.all_impls(obligation.trait_ref.def_id()); for &impl_def_id in all_impls.iter() { - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(_) => { candidates.vec.push(ImplCandidate(impl_def_id)); } @@ -848,15 +855,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: &Candidate<'tcx>) -> EvaluationResult<'tcx> { - /*! - * Further evaluate `candidate` to decide whether all type parameters match - * and whether nested obligations are met. Returns true if `candidate` remains - * viable after this further scrutiny. - */ - - debug!("winnow_candidate: depth={} candidate={}", - stack.obligation.recursion_depth, candidate.repr(self.tcx())); - let result = self.infcx.probe(|| { + debug!("winnow_candidate: candidate={}", candidate.repr(self.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), @@ -919,17 +919,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate_i.repr(self.tcx()), candidate_j.repr(self.tcx())); - self.infcx.probe(|| { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions( + &*stack.obligation.trait_ref, snapshot); let impl_substs = - self.rematch_impl(impl_def_id, stack.obligation); + self.rematch_impl(impl_def_id, stack.obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)); let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); + let poly_impl_trait_ref = + Rc::new(ty::Binder((*impl_trait_ref).clone())); let origin = infer::RelateOutputImplTypes(stack.obligation.cause.span); self.infcx - .sub_poly_trait_refs(false, origin, impl_trait_ref, vt.bound.clone()) + .sub_poly_trait_refs(false, origin, poly_impl_trait_ref, vt.bound.clone()) .is_ok() }) } @@ -1400,10 +1406,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.repr(self.tcx()), param.repr(self.tcx())); - let () = try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - param.bound.clone())); - Ok(param) + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + param.bound.clone()) { + Ok(()) => Ok(param), + Err(_) => { + self.tcx().sess.bug( + format!("Where clause `{}` was applicable to `{}` but now is not", + param.bound.repr(self.tcx()), + obligation.repr(self.tcx())).as_slice()); + } + } } fn confirm_builtin_candidate(&mut self, @@ -1476,23 +1493,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate substs={}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1)) + self.infcx.try(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + let substs = self.rematch_impl(impl_def_id, obligation, + snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)); + debug!("confirm_impl_candidate substs={}", substs); + Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, + obligation.recursion_depth + 1, skol_map, snapshot)) + }) } fn vtable_impl(&mut self, impl_def_id: ast::DefId, substs: Substs<'tcx>, cause: ObligationCause<'tcx>, - recursion_depth: uint) + recursion_depth: uint, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})", + impl_def_id.repr(self.tcx()), + substs.repr(self.tcx()), + recursion_depth, + skol_map.repr(self.tcx())); + let impl_predicates = self.impl_predicates(cause, recursion_depth, impl_def_id, - &substs); + &substs, + skol_map, + snapshot); + + debug!("vtable_impl: impl_def_id={} impl_predicates={}", + impl_def_id.repr(self.tcx()), + impl_predicates.repr(self.tcx())); + VtableImplData { impl_def_id: impl_def_id, substs: substs, nested: impl_predicates } @@ -1535,10 +1573,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: substs, })); - let () = - try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref)); + try!(self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref)); Ok(self_ty) } @@ -1582,9 +1619,52 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { closure_def_id.repr(self.tcx()), trait_ref.repr(self.tcx())); - self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref) + self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref) + } + + /// In the case of unboxed closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have an unboxed closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects an int as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(int) for Closure { ... } + /// + /// Now imagine our obligation is `Fn(uint) for Closure`. So far + /// we have matched the self-type `Closure`. At this point we'll + /// compare the `int` to `uint` and generate an error. + /// + /// Note that this checking occurs *after* the impl has selected, + /// because these output type parameters should not affect the + /// selection of the impl. Therefore, if there is a mismatch, we + /// report an error to the user. + fn confirm_poly_trait_refs(&mut self, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc>, + expected_trait_ref: Rc>) + -> Result<(), SelectionError<'tcx>> + { + let origin = infer::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_poly_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref.clone()) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } } /////////////////////////////////////////////////////////////////////////// @@ -1599,10 +1679,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn rematch_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc>) -> Substs<'tcx> { - match self.match_impl(impl_def_id, obligation) { + match self.match_impl(impl_def_id, obligation, snapshot, + skol_map, skol_obligation_trait_ref) { Ok(substs) => { substs } @@ -1618,11 +1702,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc>) -> Result, ()> { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), - impl_def_id).unwrap(); + let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types @@ -1638,15 +1724,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); - match self.match_trait_refs(obligation, impl_trait_ref) { - Ok(()) => Ok(impl_substs), - Err(()) => Err(()) + debug!("match_impl(impl_def_id={}, obligation={}, \ + impl_trait_ref={}, skol_obligation_trait_ref={})", + impl_def_id.repr(self.tcx()), + obligation.repr(self.tcx()), + impl_trait_ref.repr(self.tcx()), + skol_obligation_trait_ref.repr(self.tcx())); + + let origin = infer::RelateOutputImplTypes(obligation.cause.span); + match self.infcx.sub_trait_refs(false, + origin, + impl_trait_ref, + skol_obligation_trait_ref) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed sub_trait_refs due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } + } + + match self.infcx.leak_check(skol_map, snapshot) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed leak check due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } } + + debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx())); + Ok(impl_substs) } fn fast_reject_trait_refs(&mut self, obligation: &TraitObligation, - impl_trait_ref: &ty::PolyTraitRef) + impl_trait_ref: &ty::TraitRef) -> bool { // We can avoid creating type variables and doing the full @@ -1667,19 +1780,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - fn match_trait_refs(&mut self, - obligation: &TraitObligation<'tcx>, - trait_ref: Rc>) + fn match_where_clause(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: Rc>) -> Result<(),()> { - debug!("match_trait_refs: obligation={} trait_ref={}", + debug!("match_where_clause: obligation={} where_clause_trait_ref={}", obligation.repr(self.tcx()), - trait_ref.repr(self.tcx())); + where_clause_trait_ref.repr(self.tcx())); let origin = infer::RelateOutputImplTypes(obligation.cause.span); match self.infcx.sub_poly_trait_refs(false, origin, - trait_ref, + where_clause_trait_ref, obligation.trait_ref.clone()) { Ok(()) => Ok(()), Err(_) => Err(()), @@ -1754,78 +1867,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - /////////////////////////////////////////////////////////////////////////// - // Confirmation - // - // The final step of selection: once we know how an obligation is - // is resolved, we confirm that selection in order to have - // side-effects on the typing environment. This step also unifies - // the output type parameters from the obligation with those found - // on the impl/bound, which may yield type errors. - - /// Relates the output type parameters from an impl to the - /// trait. This may lead to type errors. The confirmation step - /// is separated from the main match procedure because these - /// type errors do not cause us to select another impl. - /// - /// As an example, consider matching the obligation - /// `Iterator for Elems` using the following impl: - /// - /// impl Iterator for Elems { ... } - /// - /// The match phase will succeed with substitution `T=int`. - /// The confirm step will then try to unify `int` and `char` - /// and yield an error. - fn confirm_impl_vtable(&mut self, - impl_def_id: ast::DefId, - obligation_cause: ObligationCause<'tcx>, - obligation_trait_ref: Rc>, - substs: &Substs<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), - impl_def_id).unwrap(); - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), - substs); - self.confirm(obligation_cause, obligation_trait_ref, impl_trait_ref) - } - - /// After we have determined which impl applies, and with what substitutions, there is one last - /// step. We have to go back and relate the "output" type parameters from the obligation to the - /// types that are specified in the impl. - /// - /// For example, imagine we have: - /// - /// impl Iterator for Vec { ... } - /// - /// and our obligation is `Iterator for Vec` (note the mismatch in the obligation - /// types). Up until this step, no error would be reported: the self type is `Vec`, and - /// that matches `Vec` with the substitution `T=int`. At this stage, we could then go and - /// check that the type parameters to the `Iterator` trait match. (In terms of the parameters, - /// the `expected_trait_ref` here would be `Iterator for Vec`, and the - /// `obligation_trait_ref` would be `Iterator for Vec`. - /// - /// Note that this checking occurs *after* the impl has selected, because these output type - /// parameters should not affect the selection of the impl. Therefore, if there is a mismatch, - /// we report an error to the user. - fn confirm(&mut self, - obligation_cause: ObligationCause, - obligation_trait_ref: Rc>, - expected_trait_ref: Rc>) - -> Result<(), SelectionError<'tcx>> - { - let origin = infer::RelateOutputImplTypes(obligation_cause.span); - - let obligation_trait_ref = obligation_trait_ref.clone(); - match self.infcx.sub_poly_trait_refs(false, - origin, - expected_trait_ref.clone(), - obligation_trait_ref.clone()) { - Ok(()) => Ok(()), - Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - } - /////////////////////////////////////////////////////////////////////////// // Miscellany @@ -1857,11 +1898,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: uint, impl_def_id: ast::DefId, - impl_substs: &Substs<'tcx>) + impl_substs: &Substs<'tcx>, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VecPerParamSpace> { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); + let bounds = self.infcx().plug_leaks(skol_map, snapshot, &bounds); util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 91247d8b73e41..ee56d919fefc7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -478,8 +478,10 @@ pub enum MethodOrigin<'tcx> { #[deriving(Clone, Show)] pub struct MethodParam<'tcx> { // the precise trait reference that occurs as a bound -- this may - // be a supertrait of what the user actually typed. - pub trait_ref: Rc>, + // be a supertrait of what the user actually typed. Note that it + // never contains bound regions; those regions should have been + // instantiated with fresh variables at this point. + pub trait_ref: Rc>, // index of uint in the list of methods for the trait pub method_num: uint, @@ -489,7 +491,7 @@ pub struct MethodParam<'tcx> { #[deriving(Clone, Show)] pub struct MethodObject<'tcx> { // the (super)trait containing the method to be invoked - pub trait_ref: Rc>, + pub trait_ref: Rc>, // the actual base trait id of the object pub object_trait_id: ast::DefId, @@ -665,7 +667,7 @@ pub struct ctxt<'tcx> { /// A cache for the trait_items() routine pub trait_items_cache: RefCell>>>>, - pub impl_trait_cache: RefCell>>>>, + pub impl_trait_cache: RefCell>>>>, pub trait_refs: RefCell>>>, pub trait_defs: RefCell>>>, @@ -1306,7 +1308,7 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { // Principal trait reference. - pub principal: PolyTraitRef<'tcx>, // would use Rc, but it runs afoul of some static rules + pub principal: PolyTraitRef<'tcx>, pub bounds: ExistentialBounds } @@ -1315,7 +1317,9 @@ impl<'tcx> TyTrait<'tcx> { /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self-type. A common choice is `mk_err()` /// or some skolemized type. - pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) -> Rc> { + pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) + -> Rc> + { Rc::new(ty::Binder(ty::TraitRef { def_id: self.principal.def_id(), substs: self.principal.substs().with_self_ty(self_ty), @@ -4818,7 +4822,7 @@ pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) } pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Option>> { + -> Option>> { memoized(&cx.impl_trait_cache, id, |id: ast::DefId| { if id.krate == ast::LOCAL_CRATE { debug!("(impl_trait_ref) searching for trait impl {}", id); @@ -4828,9 +4832,8 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) ast::ItemImpl(_, _, ref opt_trait, _, _) => { match opt_trait { &Some(ref t) => { - let trait_ref = - (*ty::node_id_to_trait_ref(cx, t.ref_id)).clone(); - Some(Rc::new(ty::Binder(trait_ref))) + let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id); + Some(trait_ref) } &None => None } @@ -5736,7 +5739,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, // Record the trait->implementation mappings, if applicable. let associated_traits = csearch::get_impl_trait(tcx, impl_def_id); for trait_ref in associated_traits.iter() { - record_trait_implementation(tcx, trait_ref.def_id(), impl_def_id); + record_trait_implementation(tcx, trait_ref.def_id, impl_def_id); } // For any methods that use a default implementation, add them to @@ -6432,26 +6435,24 @@ pub fn replace_late_bound_regions<'tcx, T, F>( debug!("replace_late_bound_regions({})", binder.repr(tcx)); let mut map = FnvHashMap::new(); - let value = { - let mut f = ty_fold::RegionFolder::new(tcx, |region, current_depth| { - debug!("region={}", region.repr(tcx)); - match region { - ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { - * match map.entry(br) { - Vacant(entry) => entry.set(mapf(br, debruijn)), - Occupied(entry) => entry.into_mut(), - } - } - _ => { - region + + // Note: fold the field `0`, not the binder, so that late-bound + // regions bound by `binder` are considered free. + let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| { + debug!("region={}", region.repr(tcx)); + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { + * match map.entry(br) { + Vacant(entry) => entry.set(mapf(br, debruijn)), + Occupied(entry) => entry.into_mut(), } } - }); + _ => { + region + } + } + }); - // Note: fold the field `0`, not the binder, so that late-bound - // regions bound by `binder` are considered free. - binder.0.fold_with(&mut f) - }; debug!("resulting map: {} value: {}", map, value.repr(tcx)); (value, map) } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 496a0badd8236..cde0470ff48e2 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -730,14 +730,17 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /// regions (aka "lifetimes") that are bound within a type are not /// visited by this folder; only regions that occur free will be /// visited by `fld_r`. -pub struct RegionFolder<'a, 'tcx: 'a, F> where F: FnMut(ty::Region, uint) -> ty::Region { + +pub struct RegionFolder<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, current_depth: uint, - fld_r: F, + fld_r: &'a mut (FnMut(ty::Region, uint) -> ty::Region + 'a), } -impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> ty::Region { - pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: F) -> RegionFolder<'a, 'tcx, F> { +impl<'a, 'tcx> RegionFolder<'a, 'tcx> { + pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> + where F : FnMut(ty::Region, uint) -> ty::Region + { RegionFolder { tcx: tcx, current_depth: 1, @@ -750,15 +753,21 @@ pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec { let mut vec = Vec::new(); - { - let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r }); - value.fold_with(&mut folder); - } + fold_regions(tcx, value, |r, _| { vec.push(r); r }); vec } -impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where - F: FnMut(ty::Region, uint) -> ty::Region, +pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, + value: &T, + mut f: F) + -> T + where F : FnMut(ty::Region, uint) -> ty::Region, + T : TypeFoldable<'tcx>, +{ + value.fold_with(&mut RegionFolder::new(tcx, &mut f)) +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } @@ -780,7 +789,7 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where _ => { debug!("RegionFolder.fold_region({}) folding free region (current_depth={})", r.repr(self.tcx()), self.current_depth); - (self.fld_r)(r, self.current_depth) + self.fld_r.call_mut((r, self.current_depth)) } } } @@ -836,7 +845,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx> debug!("shift_regions(value={}, amount={})", value.repr(tcx), amount); - value.fold_with(&mut RegionFolder::new(tcx, |region, _current_depth| { + value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| { shift_region(region, amount) })) } diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 2162055f28782..1a4f06663ef3b 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -941,14 +941,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ty::MethodTypeParam(ref mp) => { // method invoked on a type parameter let trait_item = ty::trait_item(&self.analysis.ty_cx, - mp.trait_ref.def_id(), + mp.trait_ref.def_id, mp.method_num); (None, Some(trait_item.def_id())) } ty::MethodTraitObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, - mo.trait_ref.def_id(), + mo.trait_ref.def_id, mo.method_num); (None, Some(trait_item.def_id())) } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 192b0d6342100..f8303a6f03080 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -421,12 +421,11 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id); match impl_or_trait_item { ty::MethodTraitItem(method) => { - let poly_trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); - let trait_ref = ty::erase_late_bound_regions(tcx, &*poly_trait_ref); + let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); // Compute the first substitution let first_subst = - ty::make_substs_for_receiver_types(tcx, &trait_ref, &*method) + ty::make_substs_for_receiver_types(tcx, &*trait_ref, &*method) .erase_regions(); // And compose them diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index a8f7323b4ae03..f1c3c9be396af 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -133,14 +133,14 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_num }) => { let trait_ref = - Rc::new(trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs)); + Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs))); let span = bcx.tcx().map.span(method_call.expr_id); debug!("method_call={} trait_ref={}", method_call, trait_ref.repr(bcx.tcx())); let origin = fulfill_obligation(bcx.ccx(), span, - (*trait_ref).clone()); + trait_ref.clone()); debug!("origin = {}", origin.repr(bcx.tcx())); trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(), method_num, origin) @@ -618,7 +618,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let trt_id = match ty::impl_trait_ref(tcx, impl_id) { - Some(t_id) => t_id.def_id(), + Some(t_id) => t_id.def_id, None => ccx.sess().bug("make_impl_vtable: don't know how to \ make a vtable for a type impl!") }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d6438c4062e32..4f4bebabead2c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,8 +53,7 @@ use middle::def; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; -use middle::ty::{mod, Ty}; -use middle::ty_fold; +use middle::ty::{mod, RegionEscape, Ty}; use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; @@ -533,7 +532,8 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( -> Rc> where AC: AstConv<'tcx>, RS: RegionScope { - let trait_ref = instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); + let trait_ref = + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); let trait_ref = (*trait_ref).clone(); Rc::new(ty::Binder(trait_ref)) // Ugh. } @@ -1200,10 +1200,9 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( let (self_ty, mut implied_output_region) = match opt_self_info { None => (None, None), Some(self_info) => { - // Shift regions in the self type by 1 to account for the binding - // level introduced by the function itself. - let untransformed_self_ty = - ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty); + // This type comes from an impl or trait; no late-bound + // regions should be present. + assert!(!self_info.untransformed_self_ty.has_escaping_regions()); // Figure out and record the explicit self category. let explicit_self_category = @@ -1214,19 +1213,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (None, None) } ty::ByValueExplicitSelfCategory => { - (Some(untransformed_self_ty), None) + (Some(self_info.untransformed_self_ty), None) } ty::ByReferenceExplicitSelfCategory(region, mutability) => { (Some(ty::mk_rptr(this.tcx(), region, ty::mt { - ty: untransformed_self_ty, + ty: self_info.untransformed_self_ty, mutbl: mutability })), Some(region)) } ty::ByBoxExplicitSelfCategory => { - (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None) + (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None) } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8ac58736f54b4..2c220f298262f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -222,17 +222,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // argument type), but those cases have already // been ruled out when we deemed the trait to be // "object safe". - let original_trait_ref = + let original_poly_trait_ref = data.principal_trait_ref_with_self_ty(object_ty); + let upcast_poly_trait_ref = + this.upcast(original_poly_trait_ref.clone(), trait_def_id); let upcast_trait_ref = - this.upcast(original_trait_ref.clone(), trait_def_id); - debug!("original_trait_ref={} upcast_trait_ref={} target_trait={}", - original_trait_ref.repr(this.tcx()), + this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref); + debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}", + original_poly_trait_ref.repr(this.tcx()), upcast_trait_ref.repr(this.tcx()), trait_def_id.repr(this.tcx())); - let substs = upcast_trait_ref.substs().clone(); + let substs = upcast_trait_ref.substs.clone(); let origin = MethodTraitObject(MethodObject { - trait_ref: upcast_trait_ref, + trait_ref: Rc::new(upcast_trait_ref), object_trait_id: trait_def_id, method_num: method_num, real_index: real_index, @@ -257,7 +259,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .subst(self.tcx(), &impl_polytype.substs); let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(), method_num: method_num }); - (impl_trait_ref.substs().clone(), origin) + (impl_trait_ref.substs.clone(), origin) } probe::TraitPick(trait_def_id, method_num) => { @@ -273,16 +275,20 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.infcx().next_ty_var()); let trait_ref = - Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs.clone()))); + Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) } - probe::WhereClausePick(ref trait_ref, method_num) => { - let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref.clone(), + probe::WhereClausePick(ref poly_trait_ref, method_num) => { + // Where clauses can have bound regions in them. We need to instantiate + // those to convert from a poly-trait-ref to a trait-ref. + let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref); + let substs = trait_ref.substs.clone(); + let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref), method_num: method_num }); - (trait_ref.substs().clone(), origin) + (substs, origin) } } } @@ -379,25 +385,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs: subst::Substs<'tcx>) -> InstantiatedMethodSig<'tcx> { - // If this method comes from an impl (as opposed to a trait), - // it may have late-bound regions from the impl that appear in - // the substitutions, method signature, and - // bounds. Instantiate those at this point. (If it comes from - // a trait, this step has no effect, as there are no - // late-bound regions to instantiate.) - // - // The binder level here corresponds to the impl. - let (all_substs, (method_sig, method_generics)) = - self.replace_late_bound_regions_with_fresh_var( - &ty::Binder((all_substs, - (pick.method_ty.fty.sig.clone(), - pick.method_ty.generics.clone())))); - - debug!("late-bound lifetimes from impl instantiated, \ - all_substs={} method_sig={} method_generics={}", - all_substs.repr(self.tcx()), - method_sig.repr(self.tcx()), - method_generics.repr(self.tcx())); + debug!("instantiate_method_sig(pick={}, all_substs={})", + pick.repr(self.tcx()), + all_substs.repr(self.tcx())); // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. The only @@ -427,8 +417,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs.clone() } }; - let method_bounds = - method_generics.to_bounds(self.tcx(), &method_bounds_substs); + let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs); debug!("method_bounds after subst = {}", method_bounds.repr(self.tcx())); @@ -436,7 +425,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Substitute the type/early-bound-regions into the method // signature. In addition, the method signature may bind // late-bound regions, so instantiate those. - let method_sig = method_sig.subst(self.tcx(), &all_substs); + let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs); let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig); debug!("late-bound lifetimes from method instantiated, method_sig={}", diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 451058e5e21a0..ffaeceb3eed11 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -166,12 +166,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Construct a trait-reference `self_ty : Trait` let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty); - let trait_ref = Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs))); + let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); // Construct an obligation + let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone())); let obligation = traits::Obligation::misc(span, fcx.body_id, - ty::Predicate::Trait(trait_ref.clone())); + poly_trait_ref.as_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(fcx.infcx(), @@ -194,11 +195,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Substitute the trait parameters into the method type and // instantiate late-bound regions to get the actual method type. - // - // Note that as the method comes from a trait, it can only have - // late-bound regions from the fn itself, not the impl. let ref bare_fn_ty = method_ty.fty; - let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs()); + let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; @@ -221,7 +219,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs()); + let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), &trait_ref.substs); assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( traits::ObligationCause::misc(span, fcx.body_id), @@ -293,7 +291,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(), method_num: method_num}), ty: fty, - substs: trait_ref.substs().clone() + substs: trait_ref.substs.clone() }; debug!("callee = {}", callee.repr(fcx.tcx())); @@ -379,7 +377,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None => format!(""), Some(trait_ref) => format!(" of the trait `{}`", ty::item_path_str(fcx.tcx(), - trait_ref.def_id())), + trait_ref.def_id)), }; span_note!(fcx.sess(), method_span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fc1aa59c4deb3..b5776f9aeb34a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,7 +19,6 @@ use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{mod, Ty}; -use middle::ty::{MethodObject}; use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -58,8 +57,8 @@ struct Candidate<'tcx> { enum CandidateKind<'tcx> { InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), - ObjectCandidate(MethodObject<'tcx>), - ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, + ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), + ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), WhereClauseCandidate(Rc>, MethodIndex), @@ -149,7 +148,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures - fcx.infcx().probe(|| { + fcx.infcx().probe(|_| { let (steps, opt_simplified_steps) = dummy.take().unwrap(); let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); @@ -313,12 +312,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, method_ty: m, - kind: ObjectCandidate(MethodObject { - trait_ref: new_trait_ref, - object_trait_id: trait_ref.def_id(), - method_num: method_num, - real_index: vtable_index - }) + kind: ObjectCandidate(new_trait_ref.def_id(), method_num, vtable_index) }); }); } @@ -502,7 +496,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Determine the receiver type that the method itself expects. let xform_self_ty = - self.xform_self_ty(&method, impl_trait_ref.substs()); + self.xform_self_ty(&method, &impl_trait_ref.substs); debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx())); @@ -748,7 +742,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx()), probe.repr(self.tcx())); - self.infcx().probe(|| { + self.infcx().probe(|_| { // First check that the self type can be related. match self.make_sub_ty(self_ty, probe.xform_self_ty) { Ok(()) => { } @@ -1033,8 +1027,8 @@ impl<'tcx> Candidate<'tcx> { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) } - ObjectCandidate(ref data) => { - ObjectPick(data.trait_ref.def_id(), data.method_num, data.real_index) + ObjectCandidate(def_id, method_num, real_index) => { + ObjectPick(def_id, method_num, real_index) } ExtensionImplCandidate(def_id, _, _, index) => { ExtensionImplPick(def_id, index) @@ -1059,7 +1053,7 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { InherentImplCandidate(def_id, _) => ImplSource(def_id), - ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id()), + ObjectCandidate(def_id, _, _) => TraitSource(def_id), ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), @@ -1075,7 +1069,9 @@ impl<'tcx> Candidate<'tcx> { UnboxedClosureCandidate(trait_def_id, method_num) => { Some((trait_def_id, method_num)) } - ExtensionImplCandidate(_, ref trait_ref, _, method_num) | + ExtensionImplCandidate(_, ref trait_ref, _, method_num) => { + Some((trait_ref.def_id, method_num)) + } WhereClauseCandidate(ref trait_ref, method_num) => { Some((trait_ref.def_id(), method_num)) } @@ -1096,8 +1092,8 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { match *self { InherentImplCandidate(ref a, ref b) => format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)), - ObjectCandidate(ref a) => - format!("ObjectCandidate({})", a.repr(tcx)), + ObjectCandidate(a, b, c) => + format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c), ExtensionImplCandidate(ref a, ref b, ref c, ref d) => format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx), c.repr(tcx), d), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 18f009fe6c479..9e249cc449d07 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -719,12 +719,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_env = ParameterEnvironment::for_item(ccx.tcx, method.id); let fty = ty::node_id_to_type(ccx.tcx, method.id); - debug!("fty (raw): {}", fty.repr(ccx.tcx)); - - let body_id = method.pe_body().id; - let fty = liberate_late_bound_regions( - ccx.tcx, CodeExtent::from_node_id(body_id), &ty::Binder(fty)); - debug!("fty (liberated): {}", fty.repr(ccx.tcx)); + debug!("check_method_body: fty={}", fty.repr(ccx.tcx)); check_bare_fn(ccx, &*method.pe_fn_decl(), @@ -736,11 +731,11 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, - impl_trait_ref: &ty::PolyTraitRef<'tcx>, + impl_trait_ref: &ty::TraitRef<'tcx>, impl_items: &[ast::ImplItem]) { // Locate trait methods let tcx = ccx.tcx; - let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id()); + let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id); // Check existing impl methods to see if they are both present in trait // and compatible with trait signature @@ -834,8 +829,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = ty::provided_trait_methods(tcx, - impl_trait_ref.def_id()); + let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let mut missing_methods = Vec::new(); for trait_item in trait_items.iter() { match *trait_item { @@ -894,37 +888,16 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::PolyTraitRef<'tcx>) { + impl_trait_ref: &ty::TraitRef<'tcx>) { debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); - let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id); - - // The impl's trait ref may bind late-bound regions from the impl. - // Liberate them and assign them the scope of the method body. - // - // An example would be: - // - // impl<'a> Foo<&'a T> for &'a U { ... } - // - // Here, the region parameter `'a` is late-bound, so the - // trait reference associated with the impl will be - // - // for<'a> Foo<&'a T> - // - // liberating will convert this into: - // - // Foo<&'A T> - // - // where `'A` is the `ReFree` version of `'a`. - let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_scope, impl_trait_ref); - debug!("impl_trait_ref (liberated) = {}", impl_trait_ref.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); - let trait_to_impl_substs = impl_trait_ref.substs; + let trait_to_impl_substs = &impl_trait_ref.substs; // Try to give more informative error messages about self typing // mismatches. Note that any mismatch will also be detected @@ -1060,7 +1033,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, if !check_region_bounds_on_impl_method(tcx, impl_m_span, impl_m, - impl_m_body_scope, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, @@ -1099,11 +1071,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, .map(|trait_param_def| &trait_param_def.bounds); let impl_bounds = impl_m.generics.types.get_slice(subst::FnSpace).iter() - .map(|impl_param_def| - liberate_late_bound_regions( - tcx, - impl_m_body_scope, - &ty::Binder(ty::Binder(impl_param_def.bounds.clone()))).0); + .map(|impl_param_def| &impl_param_def.bounds); for (i, (trait_param_bounds, impl_param_bounds)) in trait_bounds.zip(impl_bounds).enumerate() { @@ -1164,12 +1132,9 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, } } - // Compute skolemized form of impl and trait method tys. Note - // that we must liberate the late-bound regions from the impl. + // Compute skolemized form of impl and trait method tys. let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); - let impl_fty = liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::Binder(impl_fty)); let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); @@ -1231,7 +1196,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, impl_m: &ty::Method<'tcx>, - impl_m_body_scope: CodeExtent, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -1281,16 +1245,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_bounds = impl_param.bounds.subst(tcx, impl_to_skol_substs); - // The bounds may reference late-bound regions from the - // impl declaration. In that case, we want to replace - // those with the liberated variety so as to match the - // versions appearing in the `trait_to_skol_substs`. - // There are two-levels of binder to be aware of: the - // impl, and the method. - let impl_bounds = - ty::liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::Binder(ty::Binder(impl_bounds))).0; - debug!("check_region_bounds_on_impl_method: \ trait_param={} \ impl_param={} \ diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index a90422cd30974..c09ce3db6ddd2 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -166,11 +166,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the impl self type as seen from the "inside" -- // that is, with all type parameters converted from bound - // to free, and any late-bound regions on the impl - // liberated. + // to free. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let self_ty = liberate_late_bound_regions(fcx.tcx(), item_scope, &ty::Binder(self_ty)); bounds_checker.check_traits_in_ty(self_ty); @@ -181,7 +179,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(t) => { t } }; let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref); // There are special rules that apply to drop. if diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index e79eac90508e9..5d0bb6622c2e1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,8 +18,8 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; -use middle::region; use middle::subst::{mod, Subst}; +use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err}; @@ -339,7 +339,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // Record all the trait items. for trait_ref in associated_traits.iter() { - self.add_trait_impl(trait_ref.def_id(), impl_def_id); + self.add_trait_impl(trait_ref.def_id, impl_def_id); } // For any methods that use a default implementation, add them to @@ -459,6 +459,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let trait_impls = trait_impls.borrow().clone(); for &impl_did in trait_impls.iter() { + debug!("check_implementations_of_copy: impl_did={}", + impl_did.repr(tcx)); + if impl_did.krate != ast::LOCAL_CRATE { debug!("check_implementations_of_copy(): impl not in this \ crate"); @@ -466,20 +469,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let self_type = self.get_self_type_for_implementation(impl_did); + debug!("check_implementations_of_copy: self_type={} (bound)", + self_type.repr(tcx)); + let span = tcx.map.span(impl_did.node); - let param_env = ParameterEnvironment::for_item(tcx, - impl_did.node); + let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + assert!(!self_type.has_escaping_regions()); - // the self-type may have late-bound regions bound in the - // impl; liberate them. - let item_scope = region::CodeExtent::from_node_id(impl_did.node); - let self_type = - ty::liberate_late_bound_regions(tcx, - item_scope, - &ty::Binder(self_type)); - - debug!("can_type_implement_copy(self_type={})", + debug!("check_implementations_of_copy: self_type={} (free)", self_type.repr(tcx)); match ty::can_type_implement_copy(tcx, self_type, ¶m_env) { diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 6a24bdbb9f0ed..07a84846c47ad 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -45,7 +45,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { } Some(trait_ref) => { - let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id()); + let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id); match (trait_def.unsafety, unsafety) { (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { self.tcx.sess.span_err( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 485f0ca84304d..280b42f0959d2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -43,8 +43,8 @@ use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{mod, Ty, Polytype}; -use middle::ty_fold::{mod, TypeFolder}; +use middle::ty::{mod, RegionEscape, Ty, Polytype}; +use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; @@ -226,7 +226,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::StructVariantKind(ref struct_def) => { let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -239,7 +239,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -1050,7 +1050,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_impl( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, CreateTypeParametersForAssociatedTypes); @@ -1482,7 +1482,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) let pty = { let ty = ccx.to_ty(&ExplicitRscope, &**t); Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -1495,7 +1495,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1513,7 +1513,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1580,11 +1580,11 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> { +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ast::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics<'tcx> { ty_generics(ccx, subst::TypeSpace, generics.lifetimes.as_slice(), @@ -1664,24 +1664,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics } -fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> -{ - let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - debug!("ty_generics_for_impl: early_lifetimes={}", - early_lifetimes); - ty_generics(ccx, - subst::TypeSpace, - early_lifetimes.as_slice(), - generics.ty_params.as_slice(), - ty::Generics::empty(), - &generics.where_clause, - create_type_parameters_for_associated_types) -} - fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, @@ -2186,8 +2168,12 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, subst::Substs::new(types, regions) } -/// Verifies that the explicit self type of a method matches the impl or -/// trait. +/// Verifies that the explicit self type of a method matches the impl +/// or trait. This is a bit weird but basically because right now we +/// don't handle the general case, but instead map it to one of +/// several pre-defined options using various heuristics, this method +/// comes back to check after the fact that explicit type the user +/// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( crate_context: &CrateCtxt<'a, 'tcx>, rs: &RS, @@ -2209,19 +2195,21 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( // contain late-bound regions from the method, but not the // trait (since traits only have early-bound region // parameters). - assert!(!ty::type_escapes_depth(required_type, 1)); + assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::Binder(required_type)); + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(required_type))); - // The "base type" comes from the impl. It may have late-bound - // regions from the impl or the method. + // The "base type" comes from the impl. It too may have late-bound + // regions from the method. + assert!(!base_type.has_regions_escaping_depth(1)); let base_type_free = - ty::liberate_late_bound_regions( // liberate impl regions: + liberate_early_bound_regions( crate_context.tcx, body_scope, - &ty::liberate_late_bound_regions( // liberate method regions: - crate_context.tcx, body_scope, - &ty::Binder(ty::Binder(base_type)))); + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(base_type))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", @@ -2242,4 +2230,30 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( })); infcx.resolve_regions_and_report_errors(body_id); } + + fn liberate_early_bound_regions<'tcx,T>( + tcx: &ty::ctxt<'tcx>, + scope: region::CodeExtent, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! + * Convert early-bound regions into free regions; normally this is done by + * applying the `free_substs` from the `ParameterEnvironment`, but this particular + * method-self-type check is kind of hacky and done very early in the process, + * before we really have a `ParameterEnvironment` to check. + */ + + ty_fold::fold_regions(tcx, value, |region, _| { + match region { + ty::ReEarlyBound(id, _, _, name) => { + let def_id = local_def(id); + ty::ReFree(ty::FreeRegion { scope: scope, + bound_region: ty::BrNamed(def_id, name) }) + } + _ => region + } + }) + } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 49e45c9e56ca4..d0988af1cb473 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -281,7 +281,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it. match associated_trait { Some(ref t) => { - let trait_attrs = load_attrs(cx, tcx, t.def_id()); + let trait_attrs = load_attrs(cx, tcx, t.def_id); if trait_attrs.iter().any(|a| is_doc_hidden(a)) { return None } diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs new file mode 100644 index 0000000000000..670e871084751 --- /dev/null +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -0,0 +1,40 @@ +// 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 what an impl with only one bound region `'a` cannot be used to +// satisfy a constraint whre there are two bound regions. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_foo2() + where T : for<'a,'b> Foo<(&'a int, &'b int)> +{ +} + +fn want_foo1() + where T : for<'z> Foo<(&'z int, &'z int)> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct; + +impl<'a> Foo<(&'a int, &'a int)> for SomeStruct +{ +} + +fn a() { want_foo1::(); } // OK -- foo wants just one region +fn b() { want_foo2::(); } //~ ERROR not implemented + +fn main() { } diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs new file mode 100644 index 0000000000000..b21bae5653e22 --- /dev/null +++ b/src/test/compile-fail/hrtb-just-for-static.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 a case where you have an impl of `Foo` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_hrtb() + where T : for<'a> Foo<&'a int> +{ +} + +// AnyInt implements Foo<&'a int> for any 'a, so it is a match. +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +fn give_any() { + want_hrtb::() +} + +// StaticInt only implements Foo<&'a int> for 'a, so it is an error. +struct StaticInt; +impl Foo<&'static int> for StaticInt { } +fn give_static() { + want_hrtb::() //~ ERROR `for<'a> Foo<&'a int>` is not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-perfect-forwarding.rs b/src/test/compile-fail/hrtb-perfect-forwarding.rs new file mode 100644 index 0000000000000..a8ee2154fc396 --- /dev/null +++ b/src/test/compile-fail/hrtb-perfect-forwarding.rs @@ -0,0 +1,66 @@ +// 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 a case where you have an impl of `Foo` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&mut self, x: X) { } +} + +trait Bar { + fn bar(&mut self, x: X) { } +} + +impl<'a,X,F> Foo for &'a mut F + where F : Foo + Bar +{ +} + +impl<'a,X,F> Bar for &'a mut F + where F : Bar +{ +} + +fn no_hrtb<'b,T>(mut t: T) + where T : Bar<&'b int> +{ + // OK -- `T : Bar<&'b int>`, and thus the impl above ensures that + // `&mut T : Bar<&'b int>`. + no_hrtb(&mut t); +} + +fn bar_hrtb(mut t: T) + where T : for<'b> Bar<&'b int> +{ + // OK -- `T : for<'b> Bar<&'b int>`, and thus the impl above + // ensures that `&mut T : for<'b> Bar<&'b int>`. This is an + // example of a "perfect forwarding" impl. + bar_hrtb(&mut t); +} + +fn foo_hrtb_bar_not<'b,T>(mut t: T) + where T : for<'a> Foo<&'a int> + Bar<&'b int> +{ + // Not OK -- The forwarding impl for `Foo` requires that `Bar` also + // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a + // int>`, we require `T : for<'a> Bar<&'a int>`, but the where + // clause only specifies `T : Bar<&'b int>`. + foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> Bar<&'a int>` is not implemented for the type `T` +} + +fn foo_hrtb_bar_hrtb(mut t: T) + where T : for<'a> Foo<&'a int> + for<'b> Bar<&'b int> +{ + // OK -- now we have `T : for<'b> Bar&'b int>`. + foo_hrtb_bar_hrtb(&mut t); +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-type-outlives.rs b/src/test/compile-fail/hrtb-type-outlives.rs new file mode 100644 index 0000000000000..9a326aadc6a1c --- /dev/null +++ b/src/test/compile-fail/hrtb-type-outlives.rs @@ -0,0 +1,59 @@ +// 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 what happens when a HR obligation is applie to an impl with +// "outlives" bounds. Currently we're pretty conservative here; this +// will probably improve in time. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_foo() + where T : for<'a> Foo<&'a int> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct { + x: X +} + +impl<'a,X> Foo<&'a int> for SomeStruct + where X : 'a +{ +} + +fn one() { + // In fact there is no good reason for this to be an error, but + // whatever, I'm mostly concerned it doesn't ICE right now: + want_foo::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as shorthand + +struct AnotherStruct { + x: X +} + +impl<'a,X:'a> Foo<&'a int> for AnotherStruct +{ +} + +fn two() { + want_foo::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 01a15023fbaad..d03885ca7133c 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -11,5 +11,4 @@ fn main() { let _x = "test" as &::std::any::Any; //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` -//~^^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 51ee38d5cfed2..f5740992af48e 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -21,10 +21,15 @@ impl Foo for T { fn take_param(foo: &T) { } -fn main() { +fn a() { let x = box 3i; take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented +} +fn b() { + let x = box 3i; let y = &x; let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented } + +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index a82689b16491e..b0b37d077c170 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -20,9 +20,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 920e91958ee9e..20a4ab85d7ba8 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -20,9 +20,17 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } + diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index a7a7b1c676267..f08cff3cd6821 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -21,9 +21,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } From dab6e70e03b569c72ad74328ad91f48a2e00e44f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Dec 2014 05:44:59 -0500 Subject: [PATCH 17/24] Convert gigantic comment away from `//!` form. It is annoying to read (`//!` is intrusive) and annoying to edit (must maintain a prefix on every line). Since the only purpose of a `doc.rs` file is to have a bunch of text, using `/*!` and `*/` without indentations seems appropriate. --- src/librustc/middle/traits/doc.rs | 798 +++++++++++++++--------------- 1 file changed, 402 insertions(+), 396 deletions(-) diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index 62246b77ee940..b0addfa0bd9ad 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -8,399 +8,405 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! # TRAIT RESOLUTION -//! -//! This document describes the general process and points out some non-obvious -//! things. -//! -//! ## Major concepts -//! -//! Trait resolution is the process of pairing up an impl with each -//! reference to a trait. So, for example, if there is a generic function like: -//! -//! fn clone_slice(x: &[T]) -> Vec { ... } -//! -//! and then a call to that function: -//! -//! let v: Vec = clone_slice([1, 2, 3].as_slice()) -//! -//! it is the job of trait resolution to figure out (in which case) -//! whether there exists an impl of `int : Clone` -//! -//! Note that in some cases, like generic functions, we may not be able to -//! find a specific impl, but we can figure out that the caller must -//! provide an impl. To see what I mean, consider the body of `clone_slice`: -//! -//! fn clone_slice(x: &[T]) -> Vec { -//! let mut v = Vec::new(); -//! for e in x.iter() { -//! v.push((*e).clone()); // (*) -//! } -//! } -//! -//! The line marked `(*)` is only legal if `T` (the type of `*e`) -//! implements the `Clone` trait. Naturally, since we don't know what `T` -//! is, we can't find the specific impl; but based on the bound `T:Clone`, -//! we can say that there exists an impl which the caller must provide. -//! -//! We use the term *obligation* to refer to a trait reference in need of -//! an impl. -//! -//! ## Overview -//! -//! Trait resolution consists of three major parts: -//! -//! - SELECTION: Deciding how to resolve a specific obligation. For -//! example, selection might decide that a specific obligation can be -//! resolved by employing an impl which matches the self type, or by -//! using a parameter bound. In the case of an impl, Selecting one -//! obligation can create *nested obligations* because of where clauses -//! on the impl itself. It may also require evaluating those nested -//! obligations to resolve ambiguities. -//! -//! - FULFILLMENT: The fulfillment code is what tracks that obligations -//! are completely fulfilled. Basically it is a worklist of obligations -//! to be selected: once selection is successful, the obligation is -//! removed from the worklist and any nested obligations are enqueued. -//! -//! - COHERENCE: The coherence checks are intended to ensure that there -//! are never overlapping impls, where two impls could be used with -//! equal precedence. -//! -//! ## Selection -//! -//! Selection is the process of deciding whether an obligation can be -//! resolved and, if so, how it is to be resolved (via impl, where clause, etc). -//! The main interface is the `select()` function, which takes an obligation -//! and returns a `SelectionResult`. There are three possible outcomes: -//! -//! - `Ok(Some(selection))` -- yes, the obligation can be resolved, and -//! `selection` indicates how. If the impl was resolved via an impl, -//! then `selection` may also indicate nested obligations that are required -//! by the impl. -//! -//! - `Ok(None)` -- we are not yet sure whether the obligation can be -//! resolved or not. This happens most commonly when the obligation -//! contains unbound type variables. -//! -//! - `Err(err)` -- the obligation definitely cannot be resolved due to a -//! type error, or because there are no impls that could possibly apply, -//! etc. -//! -//! The basic algorithm for selection is broken into two big phases: -//! candidate assembly and confirmation. -//! -//! ### Candidate assembly -//! -//! Searches for impls/where-clauses/etc that might -//! possibly be used to satisfy the obligation. Each of those is called -//! a candidate. To avoid ambiguity, we want to find exactly one -//! candidate that is definitively applicable. In some cases, we may not -//! know whether an impl/where-clause applies or not -- this occurs when -//! the obligation contains unbound inference variables. -//! -//! The basic idea for candidate assembly is to do a first pass in which -//! we identify all possible candidates. During this pass, all that we do -//! is try and unify the type parameters. (In particular, we ignore any -//! nested where clauses.) Presuming that this unification succeeds, the -//! impl is added as a candidate. -//! -//! Once this first pass is done, we can examine the set of candidates. If -//! it is a singleton set, then we are done: this is the only impl in -//! scope that could possibly apply. Otherwise, we can winnow down the set -//! of candidates by using where clauses and other conditions. If this -//! reduced set yields a single, unambiguous entry, we're good to go, -//! otherwise the result is considered ambiguous. -//! -//! #### The basic process: Inferring based on the impls we see -//! -//! This process is easier if we work through some examples. Consider -//! the following trait: -//! -//! ``` -//! trait Convert { -//! fn convert(&self) -> Target; -//! } -//! ``` -//! -//! This trait just has one method. It's about as simple as it gets. It -//! converts from the (implicit) `Self` type to the `Target` type. If we -//! wanted to permit conversion between `int` and `uint`, we might -//! implement `Convert` like so: -//! -//! ```rust -//! impl Convert for int { ... } // int -> uint -//! impl Convert for uint { ... } // uint -> uint -//! ``` -//! -//! Now imagine there is some code like the following: -//! -//! ```rust -//! let x: int = ...; -//! let y = x.convert(); -//! ``` -//! -//! The call to convert will generate a trait reference `Convert<$Y> for -//! int`, where `$Y` is the type variable representing the type of -//! `y`. When we match this against the two impls we can see, we will find -//! that only one remains: `Convert for int`. Therefore, we can -//! select this impl, which will cause the type of `$Y` to be unified to -//! `uint`. (Note that while assembling candidates, we do the initial -//! unifications in a transaction, so that they don't affect one another.) -//! -//! There are tests to this effect in src/test/run-pass: -//! -//! traits-multidispatch-infer-convert-source-and-target.rs -//! traits-multidispatch-infer-convert-target.rs -//! -//! #### Winnowing: Resolving ambiguities -//! -//! But what happens if there are multiple impls where all the types -//! unify? Consider this example: -//! -//! ```rust -//! trait Get { -//! fn get(&self) -> Self; -//! } -//! -//! impl Get for T { -//! fn get(&self) -> T { *self } -//! } -//! -//! impl Get for Box { -//! fn get(&self) -> Box { box get_it(&**self) } -//! } -//! ``` -//! -//! What happens when we invoke `get_it(&box 1_u16)`, for example? In this -//! case, the `Self` type is `Box` -- that unifies with both impls, -//! because the first applies to all types, and the second to all -//! boxes. In the olden days we'd have called this ambiguous. But what we -//! do now is do a second *winnowing* pass that considers where clauses -//! and attempts to remove candidates -- in this case, the first impl only -//! applies if `Box : Copy`, which doesn't hold. After winnowing, -//! then, we are left with just one candidate, so we can proceed. There is -//! a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. -//! -//! #### Matching -//! -//! The subroutines that decide whether a particular impl/where-clause/etc -//! applies to a particular obligation. At the moment, this amounts to -//! unifying the self types, but in the future we may also recursively -//! consider some of the nested obligations, in the case of an impl. -//! -//! #### Lifetimes and selection -//! -//! Because of how that lifetime inference works, it is not possible to -//! give back immediate feedback as to whether a unification or subtype -//! relationship between lifetimes holds or not. Therefore, lifetime -//! matching is *not* considered during selection. This is reflected in -//! the fact that subregion assignment is infallible. This may yield -//! lifetime constraints that will later be found to be in error (in -//! contrast, the non-lifetime-constraints have already been checked -//! during selection and can never cause an error, though naturally they -//! may lead to other errors downstream). -//! -//! #### Where clauses -//! -//! Besides an impl, the other major way to resolve an obligation is via a -//! where clause. The selection process is always given a *parameter -//! environment* which contains a list of where clauses, which are -//! basically obligations that can assume are satisfiable. We will iterate -//! over that list and check whether our current obligation can be found -//! in that list, and if so it is considered satisfied. More precisely, we -//! want to check whether there is a where-clause obligation that is for -//! the same trait (or some subtrait) and for which the self types match, -//! using the definition of *matching* given above. -//! -//! Consider this simple example: -//! -//! trait A1 { ... } -//! trait A2 : A1 { ... } -//! -//! trait B { ... } -//! -//! fn foo { ... } -//! -//! Clearly we can use methods offered by `A1`, `A2`, or `B` within the -//! body of `foo`. In each case, that will incur an obligation like `X : -//! A1` or `X : A2`. The parameter environment will contain two -//! where-clauses, `X : A2` and `X : B`. For each obligation, then, we -//! search this list of where-clauses. To resolve an obligation `X:A1`, -//! we would note that `X:A2` implies that `X:A1`. -//! -//! ### Confirmation -//! -//! Confirmation unifies the output type parameters of the trait with the -//! values found in the obligation, possibly yielding a type error. If we -//! return to our example of the `Convert` trait from the previous -//! section, confirmation is where an error would be reported, because the -//! impl specified that `T` would be `uint`, but the obligation reported -//! `char`. Hence the result of selection would be an error. -//! -//! ### Selection during translation -//! -//! During type checking, we do not store the results of trait selection. -//! We simply wish to verify that trait selection will succeed. Then -//! later, at trans time, when we have all concrete types available, we -//! can repeat the trait selection. In this case, we do not consider any -//! where-clauses to be in scope. We know that therefore each resolution -//! will resolve to a particular impl. -//! -//! One interesting twist has to do with nested obligations. In general, in trans, -//! we only need to do a "shallow" selection for an obligation. That is, we wish to -//! identify which impl applies, but we do not (yet) need to decide how to select -//! any nested obligations. Nonetheless, we *do* currently do a complete resolution, -//! and that is because it can sometimes inform the results of type inference. That is, -//! we do not have the full substitutions in terms of the type varibales of the impl available -//! to us, so we must run trait selection to figure everything out. -//! -//! Here is an example: -//! -//! trait Foo { ... } -//! impl> Foo for Vec { ... } -//! -//! impl Bar for int { ... } -//! -//! After one shallow round of selection for an obligation like `Vec -//! : Foo`, we would know which impl we want, and we would know that -//! `T=int`, but we do not know the type of `U`. We must select the -//! nested obligation `int : Bar` to find out that `U=uint`. -//! -//! It would be good to only do *just as much* nested resolution as -//! necessary. Currently, though, we just do a full resolution. -//! -//! ## Method matching -//! -//! Method dispach follows a slightly different path than normal trait -//! selection. This is because it must account for the transformed self -//! type of the receiver and various other complications. The procedure is -//! described in `select.rs` in the "METHOD MATCHING" section. -//! -//! # Caching and subtle considerations therewith -//! -//! In general we attempt to cache the results of trait selection. This -//! is a somewhat complex process. Part of the reason for this is that we -//! want to be able to cache results even when all the types in the trait -//! reference are not fully known. In that case, it may happen that the -//! trait selection process is also influencing type variables, so we have -//! to be able to not only cache the *result* of the selection process, -//! but *replay* its effects on the type variables. -//! -//! ## An example -//! -//! The high-level idea of how the cache works is that we first replace -//! all unbound inference variables with skolemized versions. Therefore, -//! if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound -//! inference variable, we might replace it with `uint : Foo<%0>`, where -//! `%n` is a skolemized type. We would then look this up in the cache. -//! If we found a hit, the hit would tell us the immediate next step to -//! take in the selection process: i.e., apply impl #22, or apply where -//! clause `X : Foo`. Let's say in this case there is no hit. -//! Therefore, we search through impls and where clauses and so forth, and -//! we come to the conclusion that the only possible impl is this one, -//! with def-id 22: -//! -//! impl Foo for uint { ... } // Impl #22 -//! -//! We would then record in the cache `uint : Foo<%0> ==> -//! ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which -//! would (as a side-effect) unify `$1` with `int`. -//! -//! Now, at some later time, we might come along and see a `uint : -//! Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as -//! before, and hence the cache lookup would succeed, yielding -//! `ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would -//! (as a side-effect) unify `$3` with `int`. -//! -//! ## Where clauses and the local vs global cache -//! -//! One subtle interaction is that the results of trait lookup will vary -//! depending on what where clauses are in scope. Therefore, we actually -//! have *two* caches, a local and a global cache. The local cache is -//! attached to the `ParameterEnvironment` and the global cache attached -//! to the `tcx`. We use the local cache whenever the result might depend -//! on the where clauses that are in scope. The determination of which -//! cache to use is done by the method `pick_candidate_cache` in -//! `select.rs`. -//! -//! There are two cases where we currently use the local cache. The -//! current rules are probably more conservative than necessary. -//! -//! ### Trait references that involve parameter types -//! -//! The most obvious case where you need the local environment is -//! when the trait reference includes parameter types. For example, -//! consider the following function: -//! -//! impl Vec { -//! fn foo(x: T) -//! where T : Foo -//! { ... } -//! -//! fn bar(x: T) -//! { ... } -//! } -//! -//! If there is an obligation `T : Foo`, or `int : Bar`, or whatever, -//! clearly the results from `foo` and `bar` are potentially different, -//! since the set of where clauses in scope are different. -//! -//! ### Trait references with unbound variables when where clauses are in scope -//! -//! There is another less obvious interaction which involves unbound variables -//! where *only* where clauses are in scope (no impls). This manifested as -//! issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider -//! this snippet: -//! -//! ``` -//! pub trait Foo { -//! fn load_from() -> Box; -//! fn load() -> Box { -//! Foo::load_from() -//! } -//! } -//! ``` -//! -//! The default method will incur an obligation `$0 : Foo` from the call -//! to `load_from`. If there are no impls, this can be eagerly resolved to -//! `VtableParam(Self : Foo)` and cached. Because the trait reference -//! doesn't involve any parameters types (only the resolution does), this -//! result was stored in the global cache, causing later calls to -//! `Foo::load_from()` to get nonsense. -//! -//! To fix this, we always use the local cache if there are unbound -//! variables and where clauses in scope. This is more conservative than -//! necessary as far as I can tell. However, it still seems to be a simple -//! rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt -//! us in particular. -//! -//! Here is an example of the kind of subtle case that I would be worried -//! about with a more complex rule (although this particular case works -//! out ok). Imagine the trait reference doesn't directly reference a -//! where clause, but the where clause plays a role in the winnowing -//! phase. Something like this: -//! -//! ``` -//! pub trait Foo { ... } -//! pub trait Bar { ... } -//! impl Foo for T { ... } // Impl A -//! impl Foo for uint { ... } // Impl B -//! ``` -//! -//! Now, in some function, we have no where clauses in scope, and we have -//! an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` -//! and `$1=uint`: this is because for impl A to apply, `uint:Bar` would -//! have to hold, and we know it does not or else the coherence check -//! would have failed. So we might enter into our global cache: `$1 : -//! Foo<$0> => Impl B`. Then we come along in a different scope, where a -//! generic type `A` is around with the bound `A:Bar`. Now suddenly the -//! impl is viable. -//! -//! The flaw in this imaginary DOOMSDAY SCENARIO is that we would not -//! currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and -//! `$1 == char`, even though it is true that (absent type parameters) -//! there is no other type the user could enter. However, it is not -//! *completely* implausible that we *could* draw this conclusion in the -//! future; we wouldn't have to guess types, in particular, we could be -//! led by the impls. +/*! + +# TRAIT RESOLUTION + +This document describes the general process and points out some non-obvious +things. + +## Major concepts + +Trait resolution is the process of pairing up an impl with each +reference to a trait. So, for example, if there is a generic function like: + + fn clone_slice(x: &[T]) -> Vec { ... } + +and then a call to that function: + + let v: Vec = clone_slice([1, 2, 3].as_slice()) + +it is the job of trait resolution to figure out (in which case) +whether there exists an impl of `int : Clone` + +Note that in some cases, like generic functions, we may not be able to +find a specific impl, but we can figure out that the caller must +provide an impl. To see what I mean, consider the body of `clone_slice`: + + fn clone_slice(x: &[T]) -> Vec { + let mut v = Vec::new(); + for e in x.iter() { + v.push((*e).clone()); // (*) + } + } + +The line marked `(*)` is only legal if `T` (the type of `*e`) +implements the `Clone` trait. Naturally, since we don't know what `T` +is, we can't find the specific impl; but based on the bound `T:Clone`, +we can say that there exists an impl which the caller must provide. + +We use the term *obligation* to refer to a trait reference in need of +an impl. + +## Overview + +Trait resolution consists of three major parts: + +- SELECTION: Deciding how to resolve a specific obligation. For + example, selection might decide that a specific obligation can be + resolved by employing an impl which matches the self type, or by + using a parameter bound. In the case of an impl, Selecting one + obligation can create *nested obligations* because of where clauses + on the impl itself. It may also require evaluating those nested + obligations to resolve ambiguities. + +- FULFILLMENT: The fulfillment code is what tracks that obligations + are completely fulfilled. Basically it is a worklist of obligations + to be selected: once selection is successful, the obligation is + removed from the worklist and any nested obligations are enqueued. + +- COHERENCE: The coherence checks are intended to ensure that there + are never overlapping impls, where two impls could be used with + equal precedence. + +## Selection + +Selection is the process of deciding whether an obligation can be +resolved and, if so, how it is to be resolved (via impl, where clause, etc). +The main interface is the `select()` function, which takes an obligation +and returns a `SelectionResult`. There are three possible outcomes: + +- `Ok(Some(selection))` -- yes, the obligation can be resolved, and + `selection` indicates how. If the impl was resolved via an impl, + then `selection` may also indicate nested obligations that are required + by the impl. + +- `Ok(None)` -- we are not yet sure whether the obligation can be + resolved or not. This happens most commonly when the obligation + contains unbound type variables. + +- `Err(err)` -- the obligation definitely cannot be resolved due to a + type error, or because there are no impls that could possibly apply, + etc. + +The basic algorithm for selection is broken into two big phases: +candidate assembly and confirmation. + +### Candidate assembly + +Searches for impls/where-clauses/etc that might +possibly be used to satisfy the obligation. Each of those is called +a candidate. To avoid ambiguity, we want to find exactly one +candidate that is definitively applicable. In some cases, we may not +know whether an impl/where-clause applies or not -- this occurs when +the obligation contains unbound inference variables. + +The basic idea for candidate assembly is to do a first pass in which +we identify all possible candidates. During this pass, all that we do +is try and unify the type parameters. (In particular, we ignore any +nested where clauses.) Presuming that this unification succeeds, the +impl is added as a candidate. + +Once this first pass is done, we can examine the set of candidates. If +it is a singleton set, then we are done: this is the only impl in +scope that could possibly apply. Otherwise, we can winnow down the set +of candidates by using where clauses and other conditions. If this +reduced set yields a single, unambiguous entry, we're good to go, +otherwise the result is considered ambiguous. + +#### The basic process: Inferring based on the impls we see + +This process is easier if we work through some examples. Consider +the following trait: + +``` +trait Convert { + fn convert(&self) -> Target; +} +``` + +This trait just has one method. It's about as simple as it gets. It +converts from the (implicit) `Self` type to the `Target` type. If we +wanted to permit conversion between `int` and `uint`, we might +implement `Convert` like so: + +```rust +impl Convert for int { ... } // int -> uint +impl Convert for uint { ... } // uint -> uint +``` + +Now imagine there is some code like the following: + +```rust +let x: int = ...; +let y = x.convert(); +``` + +The call to convert will generate a trait reference `Convert<$Y> for +int`, where `$Y` is the type variable representing the type of +`y`. When we match this against the two impls we can see, we will find +that only one remains: `Convert for int`. Therefore, we can +select this impl, which will cause the type of `$Y` to be unified to +`uint`. (Note that while assembling candidates, we do the initial +unifications in a transaction, so that they don't affect one another.) + +There are tests to this effect in src/test/run-pass: + + traits-multidispatch-infer-convert-source-and-target.rs + traits-multidispatch-infer-convert-target.rs + +#### Winnowing: Resolving ambiguities + +But what happens if there are multiple impls where all the types +unify? Consider this example: + +```rust +trait Get { + fn get(&self) -> Self; +} + +impl Get for T { + fn get(&self) -> T { *self } +} + +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } +} +``` + +What happens when we invoke `get_it(&box 1_u16)`, for example? In this +case, the `Self` type is `Box` -- that unifies with both impls, +because the first applies to all types, and the second to all +boxes. In the olden days we'd have called this ambiguous. But what we +do now is do a second *winnowing* pass that considers where clauses +and attempts to remove candidates -- in this case, the first impl only +applies if `Box : Copy`, which doesn't hold. After winnowing, +then, we are left with just one candidate, so we can proceed. There is +a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. + +#### Matching + +The subroutines that decide whether a particular impl/where-clause/etc +applies to a particular obligation. At the moment, this amounts to +unifying the self types, but in the future we may also recursively +consider some of the nested obligations, in the case of an impl. + +#### Lifetimes and selection + +Because of how that lifetime inference works, it is not possible to +give back immediate feedback as to whether a unification or subtype +relationship between lifetimes holds or not. Therefore, lifetime +matching is *not* considered during selection. This is reflected in +the fact that subregion assignment is infallible. This may yield +lifetime constraints that will later be found to be in error (in +contrast, the non-lifetime-constraints have already been checked +during selection and can never cause an error, though naturally they +may lead to other errors downstream). + +#### Where clauses + +Besides an impl, the other major way to resolve an obligation is via a +where clause. The selection process is always given a *parameter +environment* which contains a list of where clauses, which are +basically obligations that can assume are satisfiable. We will iterate +over that list and check whether our current obligation can be found +in that list, and if so it is considered satisfied. More precisely, we +want to check whether there is a where-clause obligation that is for +the same trait (or some subtrait) and for which the self types match, +using the definition of *matching* given above. + +Consider this simple example: + + trait A1 { ... } + trait A2 : A1 { ... } + + trait B { ... } + + fn foo { ... } + +Clearly we can use methods offered by `A1`, `A2`, or `B` within the +body of `foo`. In each case, that will incur an obligation like `X : +A1` or `X : A2`. The parameter environment will contain two +where-clauses, `X : A2` and `X : B`. For each obligation, then, we +search this list of where-clauses. To resolve an obligation `X:A1`, +we would note that `X:A2` implies that `X:A1`. + +### Confirmation + +Confirmation unifies the output type parameters of the trait with the +values found in the obligation, possibly yielding a type error. If we +return to our example of the `Convert` trait from the previous +section, confirmation is where an error would be reported, because the +impl specified that `T` would be `uint`, but the obligation reported +`char`. Hence the result of selection would be an error. + +### Selection during translation + +During type checking, we do not store the results of trait selection. +We simply wish to verify that trait selection will succeed. Then +later, at trans time, when we have all concrete types available, we +can repeat the trait selection. In this case, we do not consider any +where-clauses to be in scope. We know that therefore each resolution +will resolve to a particular impl. + +One interesting twist has to do with nested obligations. In general, in trans, +we only need to do a "shallow" selection for an obligation. That is, we wish to +identify which impl applies, but we do not (yet) need to decide how to select +any nested obligations. Nonetheless, we *do* currently do a complete resolution, +and that is because it can sometimes inform the results of type inference. That is, +we do not have the full substitutions in terms of the type varibales of the impl available +to us, so we must run trait selection to figure everything out. + +Here is an example: + + trait Foo { ... } + impl> Foo for Vec { ... } + + impl Bar for int { ... } + +After one shallow round of selection for an obligation like `Vec +: Foo`, we would know which impl we want, and we would know that +`T=int`, but we do not know the type of `U`. We must select the +nested obligation `int : Bar` to find out that `U=uint`. + +It would be good to only do *just as much* nested resolution as +necessary. Currently, though, we just do a full resolution. + +## Method matching + +Method dispach follows a slightly different path than normal trait +selection. This is because it must account for the transformed self +type of the receiver and various other complications. The procedure is +described in `select.rs` in the "METHOD MATCHING" section. + +# Caching and subtle considerations therewith + +In general we attempt to cache the results of trait selection. This +is a somewhat complex process. Part of the reason for this is that we +want to be able to cache results even when all the types in the trait +reference are not fully known. In that case, it may happen that the +trait selection process is also influencing type variables, so we have +to be able to not only cache the *result* of the selection process, +but *replay* its effects on the type variables. + +## An example + +The high-level idea of how the cache works is that we first replace +all unbound inference variables with skolemized versions. Therefore, +if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound +inference variable, we might replace it with `uint : Foo<%0>`, where +`%n` is a skolemized type. We would then look this up in the cache. +If we found a hit, the hit would tell us the immediate next step to +take in the selection process: i.e., apply impl #22, or apply where +clause `X : Foo`. Let's say in this case there is no hit. +Therefore, we search through impls and where clauses and so forth, and +we come to the conclusion that the only possible impl is this one, +with def-id 22: + + impl Foo for uint { ... } // Impl #22 + +We would then record in the cache `uint : Foo<%0> ==> +ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which +would (as a side-effect) unify `$1` with `int`. + +Now, at some later time, we might come along and see a `uint : +Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as +before, and hence the cache lookup would succeed, yielding +`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would +(as a side-effect) unify `$3` with `int`. + +## Where clauses and the local vs global cache + +One subtle interaction is that the results of trait lookup will vary +depending on what where clauses are in scope. Therefore, we actually +have *two* caches, a local and a global cache. The local cache is +attached to the `ParameterEnvironment` and the global cache attached +to the `tcx`. We use the local cache whenever the result might depend +on the where clauses that are in scope. The determination of which +cache to use is done by the method `pick_candidate_cache` in +`select.rs`. + +There are two cases where we currently use the local cache. The +current rules are probably more conservative than necessary. + +### Trait references that involve parameter types + +The most obvious case where you need the local environment is +when the trait reference includes parameter types. For example, +consider the following function: + + impl Vec { + fn foo(x: T) + where T : Foo + { ... } + + fn bar(x: T) + { ... } + } + +If there is an obligation `T : Foo`, or `int : Bar`, or whatever, +clearly the results from `foo` and `bar` are potentially different, +since the set of where clauses in scope are different. + +### Trait references with unbound variables when where clauses are in scope + +There is another less obvious interaction which involves unbound variables +where *only* where clauses are in scope (no impls). This manifested as +issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider +this snippet: + +``` +pub trait Foo { + fn load_from() -> Box; + fn load() -> Box { + Foo::load_from() + } +} +``` + +The default method will incur an obligation `$0 : Foo` from the call +to `load_from`. If there are no impls, this can be eagerly resolved to +`VtableParam(Self : Foo)` and cached. Because the trait reference +doesn't involve any parameters types (only the resolution does), this +result was stored in the global cache, causing later calls to +`Foo::load_from()` to get nonsense. + +To fix this, we always use the local cache if there are unbound +variables and where clauses in scope. This is more conservative than +necessary as far as I can tell. However, it still seems to be a simple +rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt +us in particular. + +Here is an example of the kind of subtle case that I would be worried +about with a more complex rule (although this particular case works +out ok). Imagine the trait reference doesn't directly reference a +where clause, but the where clause plays a role in the winnowing +phase. Something like this: + +``` +pub trait Foo { ... } +pub trait Bar { ... } +impl Foo for T { ... } // Impl A +impl Foo for uint { ... } // Impl B +``` + +Now, in some function, we have no where clauses in scope, and we have +an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` +and `$1=uint`: this is because for impl A to apply, `uint:Bar` would +have to hold, and we know it does not or else the coherence check +would have failed. So we might enter into our global cache: `$1 : +Foo<$0> => Impl B`. Then we come along in a different scope, where a +generic type `A` is around with the bound `A:Bar`. Now suddenly the +impl is viable. + +The flaw in this imaginary DOOMSDAY SCENARIO is that we would not +currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and +`$1 == char`, even though it is true that (absent type parameters) +there is no other type the user could enter. However, it is not +*completely* implausible that we *could* draw this conclusion in the +future; we wouldn't have to guess types, in particular, we could be +led by the impls. + + + +*/ From 0b88c5d392a3a21dc3ff4202c243f6af59acaa2c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Dec 2014 05:45:14 -0500 Subject: [PATCH 18/24] Remove text on method matching, which is now out of date. --- src/librustc/middle/traits/doc.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index b0addfa0bd9ad..c435697d85ca1 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -272,13 +272,6 @@ nested obligation `int : Bar` to find out that `U=uint`. It would be good to only do *just as much* nested resolution as necessary. Currently, though, we just do a full resolution. -## Method matching - -Method dispach follows a slightly different path than normal trait -selection. This is because it must account for the transformed self -type of the receiver and various other complications. The procedure is -described in `select.rs` in the "METHOD MATCHING" section. - # Caching and subtle considerations therewith In general we attempt to cache the results of trait selection. This From aa20e2ff3609a72e400634027bcd3b9988a73757 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Dec 2014 11:40:11 -0500 Subject: [PATCH 19/24] Document new algorithm at a high-level. --- src/librustc/middle/traits/doc.rs | 119 +++++++++++++++++- .../compile-fail/hrtb-conflate-regions.rs | 4 +- src/test/compile-fail/hrtb-just-for-static.rs | 2 +- src/test/compile-fail/hrtb-type-outlives.rs | 2 +- 4 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index c435697d85ca1..80697cb3a41db 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -272,6 +272,123 @@ nested obligation `int : Bar` to find out that `U=uint`. It would be good to only do *just as much* nested resolution as necessary. Currently, though, we just do a full resolution. +# Higher-ranked trait bounds + +One of the more subtle concepts at work are *higher-ranked trait +bounds*. An example of such a bound is `for<'a> MyTrait<&'a int>`. +Let's walk through how selection on higher-ranked trait references +works. + +## Basic matching and skolemization leaks + +Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see +how it works. The test starts with the trait `Foo`: + +```rust +trait Foo { + fn foo(&self, x: X) { } +} +``` + +Let's say we have a function `want_hrtb` that wants a type which +implements `Foo<&'a int>` for any `'a`: + +```rust +fn want_hrtb() where T : for<'a> Foo<&'a int> { ... } +``` + +Now we have a struct `AnyInt` that implements `Foo<&'a int>` for any +`'a`: + +```rust +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +``` + +And the question is, does `AnyInt : for<'a> Foo<&'a int>`? We want the +answer to be yes. The algorithm for figuring it out is closely related +to the subtyping for higher-ranked types (which is described in +`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that +I recommend you read). + +1. Skolemize the obligation. +2. Match the impl against the skolemized obligation. +3. Check for skolemization leaks. + +[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +So let's work through our example. The first thing we would do is to +skolemize the obligation, yielding `AnyInt : Foo<&'0 int>` (here `'0` +represents skolemized region #0). Note that now have no quantifiers; +in terms of the compiler type, this changes from a `ty::PolyTraitRef` +to a `TraitRef`. We would then create the `TraitRef` from the impl, +using fresh variables for it's bound regions (and thus getting +`Foo<&'$a int>`, where `'$a` is the inference variable for `'a`). Next +we relate the two trait refs, yielding a graph with the constraint +that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a +leak is basically any attempt to relate a skolemized region to another +skolemized region, or to any region that pre-existed the impl match. +The leak check is done by searching from the skolemized region to find +the set of regions that it is related to in any way. This is called +the "taint" set. To pass the check, that set must consist *solely* of +itself and region variables from the impl. If the taint set includes +any other region, then the match is a failure. In this case, the taint +set for `'0` is `{'0, '$a}`, and hence the check will succeed. + +Let's consider a failure case. Imagine we also have a struct + +```rust +struct StaticInt; +impl Foo<&'static int> for StaticInt; +``` + +We want the obligation `StaticInt : for<'a> Foo<&'a int>` to be +considered unsatisfied. The check begins just as before. `'a` is +skolemized to `'0` and the impl trait reference is instantiated to +`Foo<&'static int>`. When we relate those two, we get a constraint +like `'static == '0`. This means that the taint set for `'0` is `{'0, +'static}`, which fails the leak check. + +## Higher-ranked trait obligations + +Once the basic matching is done, we get to another interesting topic: +how to deal with impl obligations. I'll work through a simple example +here. Imagine we have the traits `Foo` and `Bar` and an associated impl: + +``` +trait Foo { + fn foo(&self, x: X) { } +} + +trait Bar { + fn bar(&self, x: X) { } +} + +impl Foo for F + where F : Bar +{ +} +``` + +Now let's say we have a obligation `for<'a> Foo<&'a int>` and we match +this impl. What obligation is generated as a result? We want to get +`for<'a> Bar<&'a int>`, but how does that happen? + +After the matching, we are in a position where we have a skolemized +substitution like `X => &'0 int`. If we apply this substitution to the +impl obligations, we get `F : Bar<&'0 int>`. Obviously this is not +directly usable because the skolemized region `'0` cannot leak out of +our computation. + +What we do is to create an inverse mapping from the taint set of `'0` +back to the original bound region (`'a`, here) that `'0` resulted +from. (This is done in `higher_ranked::plug_leaks`). We know that the +leak check passed, so this taint set consists solely of the skolemized +region itself plus various intermediate region variables. We then walk +the trait-reference and convert every region in that taint set back to +a late-bound region, so in this case we'd wind up with `for<'a> F : +Bar<&'a int>`. + # Caching and subtle considerations therewith In general we attempt to cache the results of trait selection. This @@ -400,6 +517,4 @@ there is no other type the user could enter. However, it is not future; we wouldn't have to guess types, in particular, we could be led by the impls. - - */ diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs index 670e871084751..5eb8fd6931258 100644 --- a/src/test/compile-fail/hrtb-conflate-regions.rs +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test what an impl with only one bound region `'a` cannot be used to -// satisfy a constraint whre there are two bound regions. +// Test that an impl with only one bound region `'a` cannot be used to +// satisfy a constraint where there are two bound regions. trait Foo { fn foo(&self, x: X) { } diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs index b21bae5653e22..36a45400eec1a 100644 --- a/src/test/compile-fail/hrtb-just-for-static.rs +++ b/src/test/compile-fail/hrtb-just-for-static.rs @@ -27,7 +27,7 @@ fn give_any() { want_hrtb::() } -// StaticInt only implements Foo<&'a int> for 'a, so it is an error. +// StaticInt only implements Foo<&'static int>, so it is an error. struct StaticInt; impl Foo<&'static int> for StaticInt { } fn give_static() { diff --git a/src/test/compile-fail/hrtb-type-outlives.rs b/src/test/compile-fail/hrtb-type-outlives.rs index 9a326aadc6a1c..9fe8f9ab46ddc 100644 --- a/src/test/compile-fail/hrtb-type-outlives.rs +++ b/src/test/compile-fail/hrtb-type-outlives.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test what happens when a HR obligation is applie to an impl with +// Test what happens when a HR obligation is applied to an impl with // "outlives" bounds. Currently we're pretty conservative here; this // will probably improve in time. From d4f8a5abc54d3f7493ab097fb60ed4eef6920912 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Dec 2014 20:20:15 -0500 Subject: [PATCH 20/24] Work around #19982 by rewriting test impls to not use anonymous lifetimes. This currently causes an ICE; it should (ideally) work, but failing that at least give a structured error. For the purposes of this PR, though, workaround is fine. --- src/libcollections/btree/set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 8f75113c01dbf..4ef2e681992ae 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -762,8 +762,8 @@ mod test { expected: &'b [int], } - impl<'a, 'b> FnMut(&int) -> bool for Counter<'a, 'b> { - extern "rust-call" fn call_mut(&mut self, (&x,): (&int,)) -> bool { + impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> { + extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool { assert_eq!(x, self.expected[*self.i]); *self.i += 1; true From 1085012cd2f587bed0eb64a547d03d671d3a5c6f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Dec 2014 17:34:47 -0500 Subject: [PATCH 21/24] Kill some warnings about shadowed lifetimes --- src/librustc/middle/ty_fold.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index cde0470ff48e2..71e42a9dbb3de 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -711,7 +711,7 @@ pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let t1 = super_fold_ty(self, ty); @@ -769,7 +769,7 @@ pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn enter_region_binder(&mut self) { self.current_depth += 1; From 89922e52b06fbe1af74983cf2f936c5bf9e6d91e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Dec 2014 10:13:13 -0500 Subject: [PATCH 22/24] Correct comment on Binder. --- src/librustc/middle/ty.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ee56d919fefc7..6839e8bcc45db 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1368,12 +1368,13 @@ impl<'tcx> PolyTraitRef<'tcx> { } } -/// Binder serves as a synthetic binder for lifetimes. It is used when -/// we wish to replace the escaping higher-ranked lifetimes in a type -/// or something else that is not itself a binder (this is because the -/// `replace_late_bound_regions` function replaces all lifetimes bound -/// by the binder supplied to it; but a type is not a binder, so you -/// must introduce an artificial one). +/// Binder is a binder for higher-ranked lifetimes. It is part of the +/// compiler's representation for things like `for<'a> Fn(&'a int)` +/// (which would be represented by the type `PolyTraitRef == +/// Binder`). Note that when we skolemize, instantiate, +/// erase, or otherwise "discharge" these bound reons, we change the +/// type from `Binder` to just `T` (see +/// e.g. `liberate_late_bound_regions`). #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct Binder(pub T); From a04ce71172d8b51aa0d7df288bfd7333e39c763a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Dec 2014 22:16:48 -0500 Subject: [PATCH 23/24] Modify the `Bytes` type so that it remains cloneable even though it includes a `fn()`. This is really a more general problem but I wanted to ensures that `bytes` in particular remains working due to #12677. --- src/libcore/str.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 28110cf7b1a37..8fe41c0bd89c2 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -21,6 +21,7 @@ pub use self::Searcher::{Naive, TwoWay, TwoWayLong}; use char::Char; use char; +use clone::Clone; use cmp::{Eq, mod}; use default::Default; use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; @@ -31,7 +32,7 @@ use mem; use num::Int; use option::Option; use option::Option::{None, Some}; -use ops::FnMut; +use ops::{Fn, FnMut}; use ptr::RawPtr; use raw::{Repr, Slice}; use slice::{mod, SliceExt}; @@ -316,7 +317,23 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. -pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, fn(&u8) -> u8>; +pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, BytesFn>; + +/// A temporary new type wrapper that ensures that the `Bytes` iterator +/// is cloneable. +#[deriving(Copy)] +#[experimental = "iterator type instability"] +pub struct BytesFn(fn(&u8) -> u8); + +impl<'a> Fn(&'a u8) -> u8 for BytesFn { + extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { + (self.0)(ptr) + } +} + +impl Clone for BytesFn { + fn clone(&self) -> BytesFn { *self } +} /// An iterator over the substrings of a string, separated by `sep`. #[deriving(Clone)] @@ -2009,7 +2026,7 @@ impl StrPrelude for str { fn bytes(&self) -> Bytes { fn deref(&x: &u8) -> u8 { x } - self.as_bytes().iter().map(deref) + self.as_bytes().iter().map(BytesFn(deref)) } #[inline] From ebf1e4f23adba8fc2a4441b8c2a7473c3a7c9d65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Dec 2014 22:17:16 -0500 Subject: [PATCH 24/24] Three random test cases that seem to produce more errors now. I've not dug deeply into what is going on here, although the errors ARE somewhat surprising. --- src/test/compile-fail/issue-15965.rs | 5 ++++- src/test/compile-fail/issue-18345.rs | 4 +++- src/test/compile-fail/issue-18532.rs | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 935e67706589e..f3636edeaa589 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -10,7 +10,10 @@ fn main() { return - { return () } //~ ERROR the type of this value must be known in this context + { return () } +//~^ ERROR the type of this value must be known in this context +//~| ERROR this function takes 1 parameter +//~| ERROR mismatched types () ; } diff --git a/src/test/compile-fail/issue-18345.rs b/src/test/compile-fail/issue-18345.rs index 298f155faff94..c8b3463b0911d 100644 --- a/src/test/compile-fail/issue-18345.rs +++ b/src/test/compile-fail/issue-18345.rs @@ -13,7 +13,9 @@ type Transducer<'t, R, T, U> = |Step<'t, R, U>|: 't -> Step<'t, R, T>; fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> { |step| |r, x| - step(r, f(x)) //~ ERROR the type of this value must be known in this context + step(r, f(x)) + //~^ ERROR the type of this value must be known in this context + //~| ERROR this function takes 1 parameter but 2 parameters were supplied } fn main() {} diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 9cf922ae99002..ec44ab7b27705 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -17,4 +17,5 @@ fn main() { (return)((),()); //~^ ERROR the type of this value must be known + //~| ERROR this function takes 1 parameter }