提交 5a28d178 编写于 作者: N Niko Matsakis

Allow impl's to have late-bound regions. Introduces another level of

region binding at the impl site, so for method types that come from impls,
it is necessary to liberate/instantiate late-bound regions at multiple
depths.
上级 6fb68f1c
......@@ -105,8 +105,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::ItemTy(_, ref generics) |
ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) |
ast::ItemTrait(ref generics, _, _, _) |
ast::ItemImpl(ref generics, _, _, _) => {
ast::ItemTrait(ref generics, _, _, _) => {
// These kinds of items have only early bound lifetime parameters.
let lifetimes = &generics.lifetimes;
self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| {
......@@ -114,6 +113,13 @@ fn visit_item(&mut self, item: &ast::Item) {
visit::walk_item(this, item);
});
}
ast::ItemImpl(ref generics, _, _, _) => {
// Impls have both early- and late-bound lifetimes.
self.visit_early_late(subst::TypeSpace, generics, |this| {
this.check_lifetime_defs(&generics.lifetimes);
visit::walk_item(this, item);
})
}
}
}
......@@ -493,10 +499,10 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
FreeLifetimeCollector { early_bound: &mut early_bound,
late_bound: &mut late_bound };
for ty_param in generics.ty_params.iter() {
visit::walk_ty_param_bounds(&mut collector, &ty_param.bounds);
visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
}
for predicate in generics.where_clause.predicates.iter() {
visit::walk_ty_param_bounds(&mut collector, &predicate.bounds);
visit::walk_ty_param_bounds_helper(&mut collector, &predicate.bounds);
}
}
......
......@@ -100,6 +100,17 @@ pub fn is_noop(&self) -> bool {
regions_is_noop && self.types.is_empty()
}
pub fn has_regions_escaping_depth(&self, depth: uint) -> bool {
self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || {
match self.regions {
ErasedRegions =>
false,
NonerasedRegions(ref regions) =>
regions.iter().any(|r| r.escapes_depth(depth)),
}
}
}
pub fn self_ty(&self) -> Option<ty::t> {
self.types.get_self().map(|&t| t)
}
......@@ -165,6 +176,13 @@ fn map<A>(self,
NonerasedRegions(r) => NonerasedRegions(op(r, a))
}
}
pub fn is_erased(&self) -> bool {
match *self {
ErasedRegions => true,
NonerasedRegions(_) => false,
}
}
}
///////////////////////////////////////////////////////////////////////////
......@@ -391,6 +409,10 @@ pub fn iter<'a>(&'a self) -> Items<'a,T> {
self.content.iter()
}
pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
EnumeratedItems::new(self)
}
pub fn as_slice(&self) -> &[T] {
self.content.as_slice()
}
......@@ -420,6 +442,14 @@ pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
self.assoc_limit)
}
pub fn map_enumerated<U>(&self, pred: |(ParamSpace, uint, &T)| -> U) -> VecPerParamSpace<U> {
let result = self.iter_enumerated().map(pred).collect();
VecPerParamSpace::new_internal(result,
self.type_limit,
self.self_limit,
self.assoc_limit)
}
pub fn map_move<U>(self, pred: |T| -> U) -> VecPerParamSpace<U> {
let SeparateVecsPerParamSpace {
types: t,
......@@ -456,6 +486,49 @@ pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
}
}
pub struct EnumeratedItems<'a,T:'a> {
vec: &'a VecPerParamSpace<T>,
space_index: uint,
elem_index: uint
}
impl<'a,T> EnumeratedItems<'a,T> {
fn new(v: &'a VecPerParamSpace<T>) -> EnumeratedItems<'a,T> {
let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 };
result.adjust_space();
result
}
fn adjust_space(&mut self) {
let spaces = ParamSpace::all();
while
self.space_index < spaces.len() &&
self.elem_index >= self.vec.len(spaces[self.space_index])
{
self.space_index += 1;
self.elem_index = 0;
}
}
}
impl<'a,T> Iterator<(ParamSpace, uint, &'a T)> for EnumeratedItems<'a,T> {
fn next(&mut self) -> Option<(ParamSpace, uint, &'a T)> {
let spaces = ParamSpace::all();
if self.space_index < spaces.len() {
let space = spaces[self.space_index];
let index = self.elem_index;
let item = self.vec.get(space, index);
self.elem_index += 1;
self.adjust_space();
Some((space, index, item))
} else {
None
}
}
}
///////////////////////////////////////////////////////////////////////////
// Public trait `Subst`
//
......@@ -485,7 +558,8 @@ fn subst_spanned(&self,
substs: substs,
span: span,
root_ty: None,
ty_stack_depth: 0 };
ty_stack_depth: 0,
region_binders_passed: 0 };
(*self).fold_with(&mut folder)
}
}
......
......@@ -17,7 +17,7 @@
use middle::subst;
use middle::subst::Subst;
use middle::ty;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{mod, InferCtxt};
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use util::ppaux::Repr;
......@@ -38,14 +38,18 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
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);
.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;
// Determine whether `impl2` can provide an implementation for those
// same types.
let param_env = ty::empty_parameter_environment();
let mut selcx = SelectionContext::intercrate(infcx, &param_env, infcx.tcx);
let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
selcx.evaluate_impl(impl2_def_id, &obligation)
}
......
......@@ -281,33 +281,28 @@ pub fn overlapping_impls(infcx: &InferCtxt,
coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id)
}
pub fn impl_obligations(tcx: &ty::ctxt,
cause: ObligationCause,
impl_def_id: ast::DefId,
impl_substs: &subst::Substs)
-> subst::VecPerParamSpace<Obligation>
{
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
obligations_for_generics(tcx, cause, &impl_generics, impl_substs)
}
pub fn obligations_for_generics(tcx: &ty::ctxt,
cause: ObligationCause,
generics: &ty::Generics,
substs: &subst::Substs)
generic_bounds: &ty::GenericBounds,
type_substs: &subst::VecPerParamSpace<ty::t>)
-> subst::VecPerParamSpace<Obligation>
{
/*!
* Given generics for an impl like:
* Given generic bounds from an impl like:
*
* impl<A:Foo, B:Bar+Qux> ...
*
* and a substs vector like `<A=A0, B=B0>`, yields a result like
* along with the bindings for the types `A` and `B` (e.g.,
* `<A=A0, B=B0>`), yields a result like
*
* [[Foo for A0, Bar for B0, Qux for B0], [], []]
*
* Expects that `generic_bounds` have already been fully
* substituted, late-bound regions liberated and so forth,
* so that they are in the same namespace as `type_substs`.
*/
util::obligations_for_generics(tcx, cause, 0, generics, substs)
util::obligations_for_generics(tcx, cause, 0, generic_bounds, type_substs)
}
pub fn obligation_for_builtin_bound(tcx: &ty::ctxt,
......
......@@ -2017,10 +2017,10 @@ fn impl_obligations(&self,
impl_substs: &Substs)
-> VecPerParamSpace<Obligation>
{
let impl_generics = ty::lookup_item_type(self.tcx(),
impl_def_id).generics;
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
let bounds = impl_generics.to_bounds(self.tcx(), impl_substs);
util::obligations_for_generics(self.tcx(), cause, recursion_depth,
&impl_generics, impl_substs)
&bounds, &impl_substs.types)
}
}
......
......@@ -10,7 +10,7 @@
// except according to those terms.
use middle::subst;
use middle::subst::{ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::subst::{ParamSpace, Substs, VecPerParamSpace};
use middle::typeck::infer::InferCtxt;
use middle::ty;
use std::collections::HashSet;
......@@ -173,25 +173,25 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
pub fn obligations_for_generics(tcx: &ty::ctxt,
cause: ObligationCause,
recursion_depth: uint,
generics: &ty::Generics,
substs: &Substs)
generic_bounds: &ty::GenericBounds,
type_substs: &VecPerParamSpace<ty::t>)
-> VecPerParamSpace<Obligation>
{
/*! See `super::obligations_for_generics` */
debug!("obligations_for_generics(generics={}, substs={})",
generics.repr(tcx), substs.repr(tcx));
debug!("obligations_for_generics(generic_bounds={}, type_substs={})",
generic_bounds.repr(tcx), type_substs.repr(tcx));
let mut obligations = VecPerParamSpace::empty();
for def in generics.types.iter() {
for (space, index, bounds) in generic_bounds.types.iter_enumerated() {
push_obligations_for_param_bounds(tcx,
cause,
recursion_depth,
def.space,
def.index,
&def.bounds,
substs,
space,
index,
bounds,
type_substs,
&mut obligations);
}
......@@ -207,11 +207,10 @@ fn push_obligations_for_param_bounds(
space: subst::ParamSpace,
index: uint,
param_bounds: &ty::ParamBounds,
param_substs: &Substs,
param_type_substs: &VecPerParamSpace<ty::t>,
obligations: &mut VecPerParamSpace<Obligation>)
{
let param_ty = *param_substs.types.get(space, index);
let param_ty = *param_type_substs.get(space, index);
for builtin_bound in param_bounds.builtin_bounds.iter() {
let obligation = obligation_for_builtin_bound(tcx,
cause,
......@@ -225,12 +224,11 @@ fn push_obligations_for_param_bounds(
}
for bound_trait_ref in param_bounds.trait_bounds.iter() {
let bound_trait_ref = bound_trait_ref.subst(tcx, param_substs);
obligations.push(
space,
Obligation { cause: cause,
recursion_depth: recursion_depth,
trait_ref: bound_trait_ref });
trait_ref: (*bound_trait_ref).clone() });
}
}
......
......@@ -1409,6 +1409,52 @@ pub fn has_type_params(&self, space: subst::ParamSpace) -> bool {
pub fn has_region_params(&self, space: subst::ParamSpace) -> bool {
!self.regions.is_empty_in(space)
}
pub fn to_bounds(&self, tcx: &ty::ctxt, substs: &Substs) -> GenericBounds {
GenericBounds {
types: self.types.map(|d| d.bounds.subst(tcx, substs)),
regions: self.regions.map(|d| d.bounds.subst(tcx, substs)),
}
}
}
/**
* Represents the bounds declared on a particular set of type
* parameters. Should eventually be generalized into a flag list of
* where clauses. You can obtain a `GenericBounds` list from a
* `Generics` by using the `to_bounds` method. Note that this method
* reflects an important semantic invariant of `GenericBounds`: while
* the bounds in a `Generics` are expressed in terms of the bound type
* parameters of the impl/trait/whatever, a `GenericBounds` instance
* represented a set of bounds for some particular instantiation,
* meaning that the generic parameters have been substituted with
* their values.
*
* Example:
*
* struct Foo<T,U:Bar<T>> { ... }
*
* Here, the `Generics` for `Foo` would contain a list of bounds like
* `[[], [U:Bar<T>]]`. Now if there were some particular reference
* like `Foo<int,uint>`, then the `GenericBounds` would be `[[],
* [uint:Bar<int>]]`.
*/
#[deriving(Clone, Show)]
pub struct GenericBounds {
pub types: VecPerParamSpace<ParamBounds>,
pub regions: VecPerParamSpace<Vec<Region>>,
}
impl GenericBounds {
pub fn empty() -> GenericBounds {
GenericBounds { types: VecPerParamSpace::empty(),
regions: VecPerParamSpace::empty() }
}
pub fn has_escaping_regions(&self) -> bool {
self.types.any(|pb| pb.trait_bounds.iter().any(|tr| tr.has_escaping_regions())) ||
self.regions.any(|rs| rs.iter().any(|r| r.escapes_depth(0)))
}
}
impl TraitRef {
......@@ -5632,11 +5678,13 @@ pub fn construct_parameter_environment(
// Compute the bounds on Self and the type parameters.
//
let mut bounds = VecPerParamSpace::empty();
for &space in subst::ParamSpace::all().iter() {
push_bounds_from_defs(tcx, &mut bounds, space, &free_substs,
generics.types.get_slice(space));
}
let bounds = generics.to_bounds(tcx, &free_substs);
let bounds = liberate_late_bound_regions(tcx, free_id, &bind(bounds)).value;
let obligations = traits::obligations_for_generics(tcx,
traits::ObligationCause::misc(span),
&bounds,
&free_substs.types);
let type_bounds = bounds.types.subst(tcx, &free_substs);
//
// Compute region bounds. For now, these relations are stored in a
......@@ -5645,24 +5693,20 @@ pub fn construct_parameter_environment(
//
for &space in subst::ParamSpace::all().iter() {
record_region_bounds_from_defs(tcx, space, &free_substs,
generics.regions.get_slice(space));
record_region_bounds(tcx, space, &free_substs, bounds.regions.get_slice(space));
}
debug!("construct_parameter_environment: free_id={} \
free_subst={} \
bounds={}",
debug!("construct_parameter_environment: free_id={} free_subst={} \
obligations={} type_bounds={}",
free_id,
free_substs.repr(tcx),
bounds.repr(tcx));
let obligations = traits::obligations_for_generics(tcx, traits::ObligationCause::misc(span),
generics, &free_substs);
obligations.repr(tcx),
type_bounds.repr(tcx));
return ty::ParameterEnvironment {
free_substs: free_substs,
bounds: bounds,
bounds: bounds.types,
implicit_region_bound: ty::ReScope(free_id),
caller_obligations: obligations,
selection_cache: traits::SelectionCache::new(),
......@@ -5693,28 +5737,16 @@ fn push_types_from_defs(tcx: &ty::ctxt,
}
}
fn push_bounds_from_defs(tcx: &ty::ctxt,
bounds: &mut subst::VecPerParamSpace<ParamBounds>,
space: subst::ParamSpace,
free_substs: &subst::Substs,
defs: &[TypeParameterDef]) {
for def in defs.iter() {
let b = def.bounds.subst(tcx, free_substs);
bounds.push(space, b);
}
}
fn record_region_bounds_from_defs(tcx: &ty::ctxt,
space: subst::ParamSpace,
free_substs: &subst::Substs,
defs: &[RegionParameterDef]) {
for (subst_region, def) in
fn record_region_bounds(tcx: &ty::ctxt,
space: subst::ParamSpace,
free_substs: &Substs,
bound_sets: &[Vec<ty::Region>]) {
for (subst_region, bound_set) in
free_substs.regions().get_slice(space).iter().zip(
defs.iter())
bound_sets.iter())
{
// For each region parameter 'subst...
let bounds = def.bounds.subst(tcx, free_substs);
for bound_region in bounds.iter() {
for bound_region in bound_set.iter() {
// Which is declared with a bound like 'subst:'bound...
match (subst_region, bound_region) {
(&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => {
......@@ -5725,7 +5757,7 @@ fn record_region_bounds_from_defs(tcx: &ty::ctxt,
_ => {
// All named regions are instantiated with free regions.
tcx.sess.bug(
format!("push_region_bounds_from_defs: \
format!("record_region_bounds: \
non free region: {} / {}",
subst_region.repr(tcx),
bound_region.repr(tcx)).as_slice());
......
......@@ -410,6 +410,15 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics {
}
}
impl TypeFoldable for ty::GenericBounds {
fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericBounds {
ty::GenericBounds {
types: self.types.fold_with(folder),
regions: self.regions.fold_with(folder),
}
}
}
impl TypeFoldable for ty::UnsizeKind {
fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnsizeKind {
match *self {
......
......@@ -20,6 +20,7 @@
MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam};
use middle::typeck::infer;
use middle::typeck::infer::InferCtxt;
use middle::ty_fold::HigherRankedFoldable;
use syntax::ast;
use syntax::codemap::Span;
use std::rc::Rc;
......@@ -32,6 +33,27 @@ struct ConfirmContext<'a, 'tcx:'a> {
self_expr: &'a ast::Expr,
}
struct InstantiatedMethodSig {
/// Function signature of the method being invoked. The 0th
/// argument is the receiver.
method_sig: ty::FnSig,
/// Substitutions for all types/early-bound-regions declared on
/// the method.
all_substs: subst::Substs,
/// Substitution to use when adding obligations from the method
/// bounds. Normally equal to `all_substs` except for object
/// receivers. See FIXME in instantiate_method_sig() for
/// explanation.
method_bounds_substs: subst::Substs,
/// Generic bounds on the method's parameters which must be added
/// as pending obligations.
method_bounds: ty::GenericBounds,
}
pub fn confirm(fcx: &FnCtxt,
span: Span,
self_expr: &ast::Expr,
......@@ -79,14 +101,16 @@ fn confirm(&mut self,
debug!("all_substs={}", all_substs.repr(self.tcx()));
// Create the final signature for the method, replacing late-bound regions.
let method_sig = self.instantiate_method_sig(&pick, &all_substs);
let InstantiatedMethodSig {
method_sig, all_substs, method_bounds_substs, method_bounds
} = self.instantiate_method_sig(&pick, all_substs);
let method_self_ty = method_sig.inputs[0];
// Unify the (adjusted) self type with what the method expects.
self.unify_receivers(self_ty, method_self_ty);
// Add any trait/regions obligations specified on the method's type parameters.
self.add_obligations(&pick, &all_substs);
self.add_obligations(&pick, &method_bounds_substs, &method_bounds);
// Create the final `MethodCallee`.
let fty = ty::mk_bare_fn(self.tcx(), ty::BareFnTy {
......@@ -176,6 +200,10 @@ fn fresh_receiver_substs(&mut self,
* where all type and region parameters are instantiated with
* fresh variables. This substitution does not include any
* parameters declared on the method itself.
*
* Note that this substitution may include late-bound regions
* from the impl level. If so, these are instantiated later in
* the `instantiate_method_sig` routine.
*/
match pick.kind {
......@@ -354,20 +382,34 @@ fn unify_receivers(&mut self,
fn instantiate_method_sig(&mut self,
pick: &probe::Pick,
all_substs: &subst::Substs)
-> ty::FnSig
all_substs: subst::Substs)
-> InstantiatedMethodSig
{
let ref bare_fn_ty = pick.method_ty.fty;
let fn_sig = bare_fn_ty.sig.subst(self.tcx(), all_substs);
self.infcx().replace_late_bound_regions_with_fresh_var(fn_sig.binder_id,
self.span,
infer::FnCall,
&fn_sig).0
}
fn add_obligations(&mut self,
pick: &probe::Pick,
all_substs: &subst::Substs) {
// 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::bind((all_substs,
(pick.method_ty.fty.sig.clone(),
pick.method_ty.generics.clone())))).value;
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()));
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. The only
// late-bound-regions that can appear in bounds are from the
// impl, and those were already instantiated above.
//
// FIXME(DST). Super hack. For a method on a trait object
// `Trait`, the generic signature requires that
// `Self:Trait`. Since, for an object, we bind `Self` to the
......@@ -381,24 +423,54 @@ fn add_obligations(&mut self,
// obligations. This causes us to generate the obligation
// `err:Trait`, and the error type is considered to implement
// all traits, so we're all good. Hack hack hack.
match pick.kind {
let method_bounds_substs = match pick.kind {
probe::ObjectPick(..) => {
let mut temp_substs = all_substs.clone();
temp_substs.types.get_mut_slice(subst::SelfSpace)[0] = ty::mk_err();
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(self.span),
&temp_substs,
&pick.method_ty.generics);
temp_substs
}
_ => {
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(self.span),
all_substs,
&pick.method_ty.generics);
all_substs.clone()
}
};
let method_bounds =
method_generics.to_bounds(self.tcx(), &method_bounds_substs);
debug!("method_bounds after subst = {}",
method_bounds.repr(self.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 = self.replace_late_bound_regions_with_fresh_var(&method_sig);
debug!("late-bound lifetimes from method instantiated, method_sig={}",
method_sig.repr(self.tcx()));
InstantiatedMethodSig {
method_sig: method_sig,
all_substs: all_substs,
method_bounds_substs: method_bounds_substs,
method_bounds: method_bounds,
}
}
fn add_obligations(&mut self,
pick: &probe::Pick,
method_bounds_substs: &subst::Substs,
method_bounds: &ty::GenericBounds) {
debug!("add_obligations: pick={} method_bounds_substs={} method_bounds={}",
pick.repr(self.tcx()),
method_bounds_substs.repr(self.tcx()),
method_bounds.repr(self.tcx()));
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(self.span),
method_bounds_substs,
method_bounds);
}
///////////////////////////////////////////////////////////////////////////
// RECONCILIATION
......@@ -591,6 +663,13 @@ fn upcast(&mut self,
source_trait_ref.repr(self.tcx()),
target_trait_def_id.repr(self.tcx()))[]);
}
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &T) -> T
where T : HigherRankedFoldable
{
self.infcx().replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, value).0
}
}
fn wrap_autoref(mut deref: ty::AutoDerefRef,
......
......@@ -200,10 +200,12 @@ 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 = fcx.infcx().replace_late_bound_regions_with_fresh_var(fn_sig.binder_id,
span,
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
&fn_sig).0;
let transformed_self_ty = fn_sig.inputs[0];
......@@ -222,10 +224,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
// so this also effectively registers `obligation` as well. (We
// used to register `obligation` explicitly, but that resulted in
// double error messages being reported.)
//
// 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);
assert!(!method_bounds.has_escaping_regions());
fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(span),
&trait_ref.substs,
&method_ty.generics);
&method_bounds);
// FIXME(#18653) -- Try to resolve obligations, giving us more
// typing information, which can sometimes be needed to avoid
......
......@@ -17,6 +17,7 @@
use middle::subst::Subst;
use middle::traits;
use middle::ty;
use middle::ty_fold::HigherRankedFoldable;
use middle::typeck::check;
use middle::typeck::check::{FnCtxt, NoPreference};
use middle::typeck::{MethodObject};
......@@ -257,29 +258,28 @@ fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) {
ty::populate_implementations_for_type_if_necessary(self.tcx(), def_id);
for impl_infos in self.tcx().inherent_impls.borrow().get(&def_id).iter() {
for &impl_did in impl_infos.iter() {
self.assemble_inherent_impl_probe(impl_did);
for &impl_def_id in impl_infos.iter() {
self.assemble_inherent_impl_probe(impl_def_id);
}
}
}
fn assemble_inherent_impl_probe(&mut self, impl_did: ast::DefId) {
if !self.impl_dups.insert(impl_did) {
fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) {
if !self.impl_dups.insert(impl_def_id) {
return; // already visited
}
let method = match impl_method(self.tcx(), impl_did, self.method_name) {
let method = match impl_method(self.tcx(), impl_def_id, self.method_name) {
Some(m) => m,
None => { return; } // No method with correct name on this impl
};
if !self.has_applicable_self(&*method) {
// No receiver declared. Not a candidate.
return self.record_static_candidate(ImplSource(impl_did));
return self.record_static_candidate(ImplSource(impl_def_id));
}
let impl_pty = check::impl_self_ty(self.fcx, self.span, impl_did);
let impl_substs = impl_pty.substs;
let impl_substs = self.impl_substs(impl_def_id);
// Determine the receiver type that the method itself expects.
let xform_self_ty =
......@@ -288,7 +288,7 @@ fn assemble_inherent_impl_probe(&mut self, impl_did: ast::DefId) {
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
method_ty: method,
kind: InherentImplCandidate(impl_did, impl_substs)
kind: InherentImplCandidate(impl_def_id, impl_substs)
});
}
......@@ -496,8 +496,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
continue;
}
let impl_pty = check::impl_self_ty(self.fcx, self.span, impl_def_id);
let impl_substs = impl_pty.substs;
let impl_substs = self.impl_substs(impl_def_id);
debug!("impl_substs={}", impl_substs.repr(self.tcx()));
......@@ -675,7 +674,9 @@ fn search_mutabilities(&mut self,
mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t)
-> Option<PickResult>
{
let region = self.infcx().next_region_var(infer::Autoref(self.span));
// In general, during probing we erase regions. See
// `impl_self_ty()` for an explanation.
let region = ty::ReStatic;
// Search through mutabilities in order to find one where pick works:
[ast::MutImmutable, ast::MutMutable]
......@@ -746,6 +747,7 @@ fn consider_probe(&self, self_ty: ty::t, probe: &Candidate) -> bool {
probe.repr(self.tcx()));
self.infcx().probe(|| {
// First check that the self type can be related.
match self.make_sub_ty(self_ty, probe.xform_self_ty) {
Ok(()) => { }
Err(_) => {
......@@ -754,23 +756,34 @@ fn consider_probe(&self, self_ty: ty::t, probe: &Candidate) -> bool {
}
}
// If so, impls may carry other conditions (e.g., where
// clauses) that must be considered. Make sure that those
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
InherentImplCandidate(impl_def_id, ref substs) |
ExtensionImplCandidate(impl_def_id, _, ref substs, _) => {
// Check whether the impl imposes obligations we have to worry about.
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
// 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;
// Convert the bounds into obligations.
let obligations =
traits::impl_obligations(
traits::obligations_for_generics(
self.tcx(),
traits::ObligationCause::misc(self.span),
impl_def_id,
substs);
&impl_bounds,
&substs.types);
debug!("impl_obligations={}", obligations.repr(self.tcx()));
// Evaluate those obligations to see if they might possibly hold.
let mut selcx = traits::SelectionContext::new(self.infcx(),
&self.fcx.inh.param_env,
self.fcx);
obligations.all(|o| selcx.evaluate_obligation(o))
}
......@@ -883,20 +896,78 @@ fn xform_self_ty(&self, method: &Rc<ty::Method>, substs: &subst::Substs) -> ty::
self.infcx().next_ty_vars(
method.generics.types.len(subst::FnSpace));
// In general, during probe we erase regions. See
// `impl_self_ty()` for an explanation.
let method_regions =
self.infcx().region_vars_for_defs(
self.span,
method.generics.regions.get_slice(subst::FnSpace));
method.generics.regions.get_slice(subst::FnSpace)
.iter()
.map(|_| ty::ReStatic)
.collect();
placeholder = (*substs).clone().with_method(method_types, method_regions);
substs = &placeholder;
}
// Replace early-bound regions and types.
let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs);
self.infcx().replace_late_bound_regions_with_fresh_var(method.fty.sig.binder_id,
self.span,
infer::FnCall,
&xform_self_ty).0
// 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
}
fn impl_substs(&self,
impl_def_id: ast::DefId)
-> subst::Substs
{
let impl_pty = ty::lookup_item_type(self.tcx(), impl_def_id);
let type_vars =
impl_pty.generics.types.map(
|_| self.infcx().next_ty_var());
let region_placeholders =
impl_pty.generics.regions.map(
|_| ty::ReStatic); // see erase_late_bound_regions() for an expl of why 'static
subst::Substs::new(type_vars, region_placeholders)
}
fn erase_late_bound_regions<T>(&self, value: &T) -> T
where T : HigherRankedFoldable
{
/*!
* Replace late-bound-regions bound by `value` with `'static`
* using `ty::erase_late_bound_regions`.
*
* This is only a reasonable thing to do during the *probe*
* phase, not the *confirm* phase, of method matching. It is
* reasonable during the probe phase because we don't consider
* region relationships at all. Therefore, we can just replace
* all the region variables with 'static rather than creating
* fresh region variables. This is nice for two reasons:
*
* 1. Because the numbers of the region variables would
* otherwise be fairly unique to this particular method
* call, it winds up creating fewer types overall, which
* helps for memory usage. (Admittedly, this is a rather
* small effect, though measureable.)
*
* 2. It makes it easier to deal with higher-ranked trait
* bounds, because we can replace any late-bound regions
* with 'static. Otherwise, if we were going to replace
* late-bound regions with actual region variables as is
* proper, we'd have to ensure that the same region got
* replaced with the same variable, which requires a bit
* more coordination and/or tracking the substitution and
* so forth.
*/
ty::erase_late_bound_regions(self.tcx(), value)
}
}
......
......@@ -300,14 +300,14 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
}
fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation)
-> (ty::TraitRef, ty::t)
-> (Rc<ty::TraitRef>, ty::t)
{
let trait_ref =
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
&*obligation.trait_ref);
let self_ty =
trait_ref.substs.self_ty().unwrap();
(trait_ref, self_ty)
(Rc::new(trait_ref), self_ty)
}
pub fn report_fulfillment_errors(fcx: &FnCtxt,
......
......@@ -12,10 +12,10 @@
use middle::subst::{Subst};
use middle::traits;
use middle::ty;
use middle::ty::liberate_late_bound_regions;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
use middle::typeck::check::regionmanip::replace_late_bound_regions;
use middle::typeck::CrateCtxt;
use util::ppaux::Repr;
......@@ -166,16 +166,24 @@ fn check_impl(&mut self,
let mut bounds_checker = BoundsChecker::new(fcx, item.span,
item.id, Some(&mut this.cache));
// 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.
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.id, &ty::bind(self_ty)).value;
bounds_checker.check_traits_in_ty(self_ty);
// Similarly, obtain an "inside" reference to the trait
// that the impl implements.
let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) {
None => { return; }
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.id, &trait_ref);
// There are special rules that apply to drop.
if
......@@ -215,7 +223,6 @@ fn check_impl(&mut self,
// FIXME -- This is a bit ill-factored. There is very similar
// code in traits::util::obligations_for_generics.
fcx.add_region_obligations_for_type_parameter(item.span,
ty::ParamTy::for_self(trait_ref.def_id),
&trait_def.bounds,
trait_ref.self_ty());
for builtin_bound in trait_def.bounds.builtin_bounds.iter() {
......@@ -280,12 +287,13 @@ pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef) {
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);
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(
self.span,
traits::ItemObligation(trait_ref.def_id)),
&trait_ref.substs,
&trait_def.generics);
&bounds);
for &ty in trait_ref.substs.types.iter() {
self.check_traits_in_ty(ty);
......@@ -335,7 +343,7 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
traits::ObligationCause::new(self.span,
traits::ItemObligation(type_id)),
substs,
&polytype.generics);
&polytype.generics.to_bounds(self.tcx(), substs));
} else {
// There are two circumstances in which we ignore
// region obligations.
......@@ -363,7 +371,7 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
traits::ObligationCause::new(self.span,
traits::ItemObligation(type_id)),
substs,
&polytype.generics);
&polytype.generics.to_bounds(self.tcx(), substs));
}
self.fold_substs(substs);
......
......@@ -1112,10 +1112,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(ref method) => {
let body_id = method.pe_body().id;
check_method_self_type(ccx,
&BindingRscope::new(method.id),
&BindingRscope::new(),
selfty,
method.pe_explicit_self());
method.pe_explicit_self(),
body_id);
methods.push(&**method);
}
ast::TypeImplItem(ref typedef) => {
......@@ -1170,17 +1172,19 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
local_def(it.id));
match *trait_method {
ast::RequiredMethod(ref type_method) => {
let rscope = BindingRscope::new(type_method.id);
let rscope = BindingRscope::new();
check_method_self_type(ccx,
&rscope,
self_type,
&type_method.explicit_self)
&type_method.explicit_self,
it.id)
}
ast::ProvidedMethod(ref method) => {
check_method_self_type(ccx,
&BindingRscope::new(method.id),
&BindingRscope::new(),
self_type,
method.pe_explicit_self())
method.pe_explicit_self(),
it.id)
}
ast::TypeTraitItem(ref associated_type) => {
convert_associated_type(ccx,
......@@ -2132,10 +2136,12 @@ pub fn mk_item_substs(ccx: &CrateCtxt,
/// Verifies that the explicit self type of a method matches the impl or
/// trait.
fn check_method_self_type<RS:RegionScope>(
crate_context: &CrateCtxt,
rs: &RS,
required_type: ty::t,
explicit_self: &ast::ExplicitSelf) {
crate_context: &CrateCtxt,
rs: &RS,
required_type: ty::t,
explicit_self: &ast::ExplicitSelf,
body_id: ast::NodeId)
{
match explicit_self.node {
ast::SelfExplicit(ref ast_type, _) => {
let typ = crate_context.to_ty(rs, &**ast_type);
......@@ -2144,13 +2150,44 @@ fn check_method_self_type<RS:RegionScope>(
ty::ty_uniq(typ) => typ,
_ => typ,
};
// "Required type" comes from the trait definition. It may
// 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));
let required_type_free =
ty::liberate_late_bound_regions(
crate_context.tcx,
body_id,
&ty::bind(required_type)).value;
// 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_id,
&ty::bind(ty::bind(base_type))).value.value;
let base_type_free = // liberate method regions:
ty::liberate_late_bound_regions(
crate_context.tcx,
body_id,
&ty::bind(base_type_free)).value;
debug!("required_type={} required_type_free={} \
base_type={} base_type_free={}",
required_type.repr(crate_context.tcx),
required_type_free.repr(crate_context.tcx),
base_type.repr(crate_context.tcx),
base_type_free.repr(crate_context.tcx));
let infcx = infer::new_infer_ctxt(crate_context.tcx);
drop(typeck::require_same_types(crate_context.tcx,
Some(&infcx),
false,
explicit_self.span,
base_type,
required_type,
base_type_free,
required_type_free,
|| {
format!("mismatched self type: expected `{}`",
ppaux::ty_to_string(crate_context.tcx, required_type))
......
......@@ -650,14 +650,12 @@ fn report_concrete_failure(&self,
sup,
"");
}
infer::RelateParamBound(span, param_ty, ty) => {
infer::RelateParamBound(span, ty) => {
self.tcx.sess.span_err(
span,
format!("the type `{}` (provided as the value of \
the parameter `{}`) does not fulfill the \
format!("the type `{}` does not fulfill the \
required lifetime",
self.ty_to_string(ty),
param_ty.user_string(self.tcx)).as_slice());
self.ty_to_string(ty)).as_slice());
note_and_explain_region(self.tcx,
"type must outlive ",
sub,
......@@ -1651,13 +1649,11 @@ fn note_region_origin(&self, origin: &SubregionOrigin) {
does not outlive the data it points at",
self.ty_to_string(ty)).as_slice());
}
infer::RelateParamBound(span, param_ty, t) => {
infer::RelateParamBound(span, t) => {
self.tcx.sess.span_note(
span,
format!("...so that the parameter `{}`, \
when instantiated with `{}`, \
will meet its declared lifetime bounds.",
param_ty.user_string(self.tcx),
format!("...so that the type `{}` \
will meet the declared lifetime bounds.",
self.ty_to_string(t)).as_slice());
}
infer::RelateDefaultParamBound(span, t) => {
......
......@@ -184,9 +184,9 @@ pub enum SubregionOrigin {
// type of the variable outlives the lifetime bound.
RelateProcBound(Span, ast::NodeId, ty::t),
// The given type parameter was instantiated with the given type,
// Some type parameter was instantiated with the given type,
// and that type must outlive some region.
RelateParamBound(Span, ty::ParamTy, ty::t),
RelateParamBound(Span, ty::t),
// The given region parameter was instantiated with a region
// that must outlive some other region.
......@@ -1062,7 +1062,7 @@ pub fn span(&self) -> Span {
IndexSlice(a) => a,
RelateObjectBound(a) => a,
RelateProcBound(a, _, _) => a,
RelateParamBound(a, _, _) => a,
RelateParamBound(a, _) => a,
RelateRegionParamBound(a) => a,
RelateDefaultParamBound(a, _) => a,
Reborrow(a) => a,
......@@ -1112,11 +1112,10 @@ fn repr(&self, tcx: &ty::ctxt) -> String {
b,
c.repr(tcx))
}
RelateParamBound(a, b, c) => {
format!("RelateParamBound({},{},{})",
RelateParamBound(a, b) => {
format!("RelateParamBound({},{})",
a.repr(tcx),
b.repr(tcx),
c.repr(tcx))
b.repr(tcx))
}
RelateRegionParamBound(a) => {
format!("RelateRegionParamBound({})",
......
......@@ -731,6 +731,9 @@ fn repr(&self, tcx: &ctxt) -> String {
impl Repr for ty::TraitRef {
fn repr(&self, tcx: &ctxt) -> String {
// when printing out the debug representation, we don't need
// to enumerate the `for<...>` etc because the debruijn index
// 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!("<{} : {}>",
......@@ -921,6 +924,14 @@ fn repr(&self, tcx: &ctxt) -> String {
}
}
impl Repr for ty::GenericBounds {
fn repr(&self, tcx: &ctxt) -> String {
format!("GenericBounds(types: {}, regions: {})",
self.types.repr(tcx),
self.regions.repr(tcx))
}
}
impl Repr for ty::ItemVariances {
fn repr(&self, tcx: &ctxt) -> String {
format!("ItemVariances(types={}, \
......@@ -1139,9 +1150,41 @@ fn user_string(&self, tcx: &ctxt) -> String {
impl UserString for ty::TraitRef {
fn user_string(&self, tcx: &ctxt) -> String {
let base = ty::item_path_str(tcx, self.def_id);
// Replace any anonymous late-bound regions with named
// variants, using gensym'd identifiers, so that we can
// clearly differentiate between named and unnamed regions in
// 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| {
ty::ReLateBound(debruijn, match br {
ty::BrNamed(_, name) => {
names.push(token::get_name(name));
br
}
ty::BrAnon(_) |
ty::BrFresh(_) |
ty::BrEnv => {
let name = token::gensym("r");
names.push(token::get_name(name));
ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name)
}
})
});
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_def = ty::lookup_trait_def(tcx, self.def_id);
parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)
parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics)
}
}
......
......@@ -467,9 +467,8 @@ pub fn trans_fn_ref_with_substs(
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)
.expect("could not find trait_ref for impl with \
default methods");
let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap();
let trait_ref = ty::erase_late_bound_regions(tcx, &trait_ref);
// Compute the first substitution
let first_subst =
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册