rollup merge of #21252: nikomatsakis/assoc-type-ice-hunt-take-2
Project region bounds out of the trait when deciding whether a projection type outlives a given regions. Fixes #20890. Fixes #21150.
This commit is contained in:
commit
036d8c4189
10 changed files with 384 additions and 2 deletions
|
@ -84,6 +84,7 @@ pub struct FulfillmentContext<'tcx> {
|
|||
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RegionObligation<'tcx> {
|
||||
pub sub_region: ty::Region,
|
||||
pub sup_type: Ty<'tcx>,
|
||||
|
|
|
@ -297,14 +297,25 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
|||
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
|
||||
{
|
||||
debug!("visit_region_obligations: node_id={}", node_id);
|
||||
let fulfillment_cx = self.fcx.inh.fulfillment_cx.borrow();
|
||||
for r_o in fulfillment_cx.region_obligations(node_id).iter() {
|
||||
|
||||
// Make a copy of the region obligations vec because we'll need
|
||||
// to be able to borrow the fulfillment-cx below when projecting.
|
||||
let region_obligations =
|
||||
self.fcx.inh.fulfillment_cx.borrow()
|
||||
.region_obligations(node_id)
|
||||
.to_vec();
|
||||
|
||||
for r_o in region_obligations.iter() {
|
||||
debug!("visit_region_obligations: r_o={}",
|
||||
r_o.repr(self.tcx()));
|
||||
let sup_type = self.resolve_type(r_o.sup_type);
|
||||
let origin = infer::RelateRegionParamBound(r_o.cause.span);
|
||||
type_must_outlive(self, origin, sup_type, r_o.sub_region);
|
||||
}
|
||||
|
||||
// Processing the region obligations should not cause the list to grow further:
|
||||
assert_eq!(region_obligations.len(),
|
||||
self.fcx.inh.fulfillment_cx.borrow().region_obligations(node_id).len());
|
||||
}
|
||||
|
||||
/// This method populates the region map's `free_region_map`. It walks over the transformed
|
||||
|
@ -1480,6 +1491,15 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
generic.to_ty(rcx.tcx()),
|
||||
param_env.caller_bounds.predicates.as_slice().to_vec());
|
||||
|
||||
// In the case of a projection T::Foo, we may be able to extract bounds from the trait def:
|
||||
match *generic {
|
||||
GenericKind::Param(..) => { }
|
||||
GenericKind::Projection(ref projection_ty) => {
|
||||
param_bounds.push_all(
|
||||
&projection_bounds(rcx, origin.span(), projection_ty)[]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
param_bounds.push(param_env.implicit_region_bound);
|
||||
|
@ -1511,3 +1531,73 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
region,
|
||||
param_bounds);
|
||||
}
|
||||
|
||||
fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
span: Span,
|
||||
projection_ty: &ty::ProjectionTy<'tcx>)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
let fcx = rcx.fcx;
|
||||
let tcx = fcx.tcx();
|
||||
let infcx = fcx.infcx();
|
||||
|
||||
debug!("projection_bounds(projection_ty={})",
|
||||
projection_ty.repr(tcx));
|
||||
|
||||
let ty = ty::mk_projection(tcx, projection_ty.trait_ref.clone(), projection_ty.item_name);
|
||||
|
||||
// Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
|
||||
// in looking for a trait definition like:
|
||||
//
|
||||
// ```
|
||||
// trait SomeTrait<'a> {
|
||||
// type SomeType : 'a;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
|
||||
let trait_def = ty::lookup_trait_def(tcx, projection_ty.trait_ref.def_id);
|
||||
let predicates = trait_def.generics.predicates.as_slice().to_vec();
|
||||
traits::elaborate_predicates(tcx, predicates)
|
||||
.filter_map(|predicate| {
|
||||
// we're only interesting in `T : 'a` style predicates:
|
||||
let outlives = match predicate {
|
||||
ty::Predicate::TypeOutlives(data) => data,
|
||||
_ => { return None; }
|
||||
};
|
||||
|
||||
debug!("projection_bounds: outlives={} (1)",
|
||||
outlives.repr(tcx));
|
||||
|
||||
// apply the substitutions (and normalize any projected types)
|
||||
let outlives = fcx.instantiate_type_scheme(span,
|
||||
projection_ty.trait_ref.substs,
|
||||
&outlives);
|
||||
|
||||
debug!("projection_bounds: outlives={} (2)",
|
||||
outlives.repr(tcx));
|
||||
|
||||
let region_result = infcx.try(|_| {
|
||||
let (outlives, _) =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
span,
|
||||
infer::AssocTypeProjection(projection_ty.item_name),
|
||||
&outlives);
|
||||
|
||||
debug!("projection_bounds: outlives={} (3)",
|
||||
outlives.repr(tcx));
|
||||
|
||||
// check whether this predicate applies to our current projection
|
||||
match infer::mk_eqty(infcx, false, infer::Misc(span), ty, outlives.0) {
|
||||
Ok(()) => { Ok(outlives.1) }
|
||||
Err(_) => { Err(()) }
|
||||
}
|
||||
});
|
||||
|
||||
debug!("projection_bounds: region_result={}",
|
||||
region_result.repr(tcx));
|
||||
|
||||
region_result.ok()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the compiler checks that arbitrary region bounds declared
|
||||
// in the trait must be satisfied on the impl. Issue #20890.
|
||||
|
||||
trait Foo<'a> { type Value: 'a; }
|
||||
|
||||
impl<'a> Foo<'a> for &'a i16 {
|
||||
// OK.
|
||||
type Value = &'a i32;
|
||||
}
|
||||
|
||||
impl<'a> Foo<'static> for &'a i32 {
|
||||
//~^ ERROR cannot infer
|
||||
type Value = &'a i32;
|
||||
}
|
||||
|
||||
impl<'a,'b> Foo<'b> for &'a i64 {
|
||||
//~^ ERROR cannot infer
|
||||
type Value = &'a i32;
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the compiler checks that the 'static bound declared in
|
||||
// the trait must be satisfied on the impl. Issue #20890.
|
||||
|
||||
trait Foo { type Value: 'static; }
|
||||
|
||||
impl<'a> Foo for &'a i32 {
|
||||
//~^ ERROR cannot infer
|
||||
type Value = &'a i32;
|
||||
}
|
||||
|
||||
impl<'a> Foo for i32 {
|
||||
// OK.
|
||||
type Value = i32;
|
||||
}
|
||||
|
||||
fn main() { }
|
34
src/test/run-fail/issue-20971.rs
Normal file
34
src/test/run-fail/issue-20971.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for Issue #20971.
|
||||
|
||||
// error-pattern:Hello, world!
|
||||
|
||||
pub trait Parser {
|
||||
type Input;
|
||||
fn parse(&mut self, input: <Self as Parser>::Input);
|
||||
}
|
||||
|
||||
impl Parser for () {
|
||||
type Input = ();
|
||||
fn parse(&mut self, input: ()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn many() -> Box<Parser<Input=<() as Parser>::Input> + 'static> {
|
||||
panic!("Hello, world!")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
many()
|
||||
.parse(());
|
||||
}
|
32
src/test/run-pass/issue-20763-1.rs
Normal file
32
src/test/run-pass/issue-20763-1.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait T0 { type O; }
|
||||
|
||||
struct S<A>(A);
|
||||
impl<A> T0 for S<A> { type O = A; }
|
||||
|
||||
trait T1: T0 {
|
||||
// this looks okay but as we see below, `f` is unusable
|
||||
fn m0<F: Fn(<Self as T0>::O) -> bool>(self, f: F) -> bool;
|
||||
}
|
||||
|
||||
// complains about the bounds on F here not being required by the trait
|
||||
impl<A> T1 for S<A> {
|
||||
fn m0<F: Fn(A) -> bool>(self, f: F) -> bool { f(self.0) }
|
||||
}
|
||||
|
||||
// // complains about mismatched types: <S<A> as T0>::O vs. A
|
||||
// impl<A> T1 for S<A>
|
||||
// {
|
||||
// fn m0<F: Fn(<Self as T0>::O) -> bool>(self, f: F) -> bool { f(self.0) }
|
||||
// }
|
||||
|
||||
fn main() { }
|
27
src/test/run-pass/issue-20763-2.rs
Normal file
27
src/test/run-pass/issue-20763-2.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait T0 { type O; }
|
||||
|
||||
struct S<A>(A);
|
||||
impl<A> T0 for S<A> { type O = A; }
|
||||
|
||||
trait T1: T0 {
|
||||
// this looks okay but as we see below, `f` is unusable
|
||||
fn m0<F: Fn(<Self as T0>::O) -> bool>(self, f: F) -> bool;
|
||||
}
|
||||
|
||||
// complains about mismatched types: <S<A> as T0>::O vs. A
|
||||
impl<A> T1 for S<A>
|
||||
{
|
||||
fn m0<F: Fn(<Self as T0>::O) -> bool>(self, f: F) -> bool { f(self.0) }
|
||||
}
|
||||
|
||||
fn main() { }
|
91
src/test/run-pass/issue-20797.rs
Normal file
91
src/test/run-pass/issue-20797.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #20797.
|
||||
|
||||
use std::default::Default;
|
||||
use std::io::IoResult;
|
||||
use std::io::fs;
|
||||
use std::io::fs::PathExtensions;
|
||||
|
||||
/// A strategy for acquiring more subpaths to walk.
|
||||
pub trait Strategy {
|
||||
type P: PathExtensions;
|
||||
/// Get additional subpaths from a given path.
|
||||
fn get_more(&self, item: &Self::P) -> IoResult<Vec<Self::P>>;
|
||||
/// Determine whether a path should be walked further.
|
||||
/// This is run against each item from `get_more()`.
|
||||
fn prune(&self, p: &Self::P) -> bool;
|
||||
}
|
||||
|
||||
/// The basic fully-recursive strategy. Nothing is pruned.
|
||||
#[derive(Copy, Default)]
|
||||
pub struct Recursive;
|
||||
|
||||
impl Strategy for Recursive {
|
||||
type P = Path;
|
||||
fn get_more(&self, p: &Path) -> IoResult<Vec<Path>> { fs::readdir(p) }
|
||||
|
||||
fn prune(&self, _: &Path) -> bool { false }
|
||||
}
|
||||
|
||||
/// A directory walker of `P` using strategy `S`.
|
||||
pub struct Subpaths<S: Strategy> {
|
||||
stack: Vec<S::P>,
|
||||
strategy: S,
|
||||
}
|
||||
|
||||
impl<S: Strategy> Subpaths<S> {
|
||||
/// Create a directory walker with a root path and strategy.
|
||||
pub fn new(p: &S::P, strategy: S) -> IoResult<Subpaths<S>> {
|
||||
let stack = try!(strategy.get_more(p));
|
||||
Ok(Subpaths { stack: stack, strategy: strategy })
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Default + Strategy> Subpaths<S> {
|
||||
/// Create a directory walker with a root path and a default strategy.
|
||||
pub fn walk(p: &S::P) -> IoResult<Subpaths<S>> {
|
||||
Subpaths::new(p, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Default + Strategy> Default for Subpaths<S> {
|
||||
fn default() -> Subpaths<S> {
|
||||
Subpaths { stack: Vec::new(), strategy: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Strategy> Iterator for Subpaths<S> {
|
||||
type Item = S::P;
|
||||
fn next (&mut self) -> Option<S::P> {
|
||||
let mut opt_path = self.stack.pop();
|
||||
while opt_path.is_some() && self.strategy.prune(opt_path.as_ref().unwrap()) {
|
||||
opt_path = self.stack.pop();
|
||||
}
|
||||
match opt_path {
|
||||
Some(path) => {
|
||||
if PathExtensions::is_dir(&path) {
|
||||
let result = self.strategy.get_more(&path);
|
||||
match result {
|
||||
Ok(dirs) => { self.stack.extend(dirs.into_iter()); },
|
||||
Err(..) => { }
|
||||
}
|
||||
}
|
||||
Some(path)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut walker: Subpaths<Recursive> = Subpaths::walk(&Path::new("/home")).unwrap();
|
||||
}
|
28
src/test/run-pass/regions-assoc-type-region-bound.rs
Normal file
28
src/test/run-pass/regions-assoc-type-region-bound.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the compiler considers the 'a bound declared in the
|
||||
// trait. Issue #20890.
|
||||
|
||||
trait Foo<'a> {
|
||||
type Value: 'a;
|
||||
|
||||
fn get(&self) -> &'a Self::Value;
|
||||
}
|
||||
|
||||
fn takes_foo<'a,F: Foo<'a>>(f: &'a F) {
|
||||
// This call would be illegal, because it results in &'a F::Value,
|
||||
// and the only way we know that `F::Value : 'a` is because of the
|
||||
// trait declaration.
|
||||
|
||||
f.get();
|
||||
}
|
||||
|
||||
fn main() { }
|
22
src/test/run-pass/regions-assoc-type-static-bound.rs
Normal file
22
src/test/run-pass/regions-assoc-type-static-bound.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the compiler considers the 'static bound declared in the
|
||||
// trait. Issue #20890.
|
||||
|
||||
trait Foo { type Value: 'static; }
|
||||
|
||||
fn require_static<T: 'static>() {}
|
||||
|
||||
fn takes_foo<F: Foo>() {
|
||||
require_static::<F::Value>()
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
Reference in a new issue