Auto merge of #39305 - eddyb:synelide, r=nikomatsakis

Perform lifetime elision (more) syntactically, before type-checking.

The *initial* goal of this patch was to remove the (contextual) `&RegionScope` argument passed around `rustc_typeck::astconv` and allow converting arbitrary (syntactic) `hir::Ty` to (semantic) `Ty`.
I've tried to closely match the existing behavior while moving the logic to the earlier `resolve_lifetime` pass, and [the crater report](https://gist.github.com/eddyb/4ac5b8516f87c1bfa2de528ed2b7779a) suggests none of the changes broke real code, but I will try to list everything:

There are few cases in lifetime elision that could trip users up due to "hidden knowledge":
```rust
type StaticStr = &'static str; // hides 'static
trait WithLifetime<'a> {
    type Output; // can hide 'a
}

// This worked because the type of the first argument contains
// 'static, although StaticStr doesn't even have parameters.
fn foo(x: StaticStr) -> &str { x }

// This worked because the compiler resolved the argument type
// to <T as WithLifetime<'a>>::Output which has the hidden 'a.
fn bar<'a, T: WithLifetime<'a>>(_: T::Output) -> &str { "baz" }
```

In the two examples above, elision wasn't using lifetimes that were in the source, not even *needed* by paths in the source, but rather *happened* to be part of the semantic representation of the types.
To me, this suggests they should have never worked through elision (and they don't with this PR).

Next we have an actual rule with a strange result, that is, the return type here elides to `&'x str`:
```rust
impl<'a, 'b> Trait for Foo<'a, 'b> {
    fn method<'x, 'y>(self: &'x Foo<'a, 'b>, _: Bar<'y>) -> &str {
        &self.name
    }
}
```
All 3 of `'a`, `'b` and `'y` are being ignored, because the `&self` elision rule only cares that the first argument is "`self` by reference". Due implementation considerations (elision running before typeck), I've limited it in this PR to a reference to a primitive/`struct`/`enum`/`union`, but not other types, but I am doing another crater run to assess the impact of limiting it to literally `&self` and `self: &Self` (they're identical in HIR).

It's probably ideal to keep an "implicit `Self` for `self`" type around and *only* apply the rule to `&self` itself, but that would result in more bikeshed, and #21400 suggests some people expect otherwise.
Another decent option is treating `self: X, ... -> Y` like `X -> Y` (one unique lifetime in `X` used for `Y`).

The remaining changes have to do with "object lifetime defaults" (see RFCs [599](https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md) and [1156](https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md)):
```rust
trait Trait {}
struct Ref2<'a, 'b, T: 'a+'b>(&'a T, &'b T);

// These apply specifically within a (fn) body,
// which allows type and lifetime inference:
fn main() {
    // Used to be &'a mut (Trait+'a) - where 'a is one
    // inference variable - &'a mut (Trait+'b) in this PR.
    let _: &mut Trait;

    // Used to be an ambiguity error, but in this PR it's
    // Ref2<'a, 'b, Trait+'c> (3 inference variables).
    let _: Ref2<Trait>;
}
```
What's happening here is that inference variables are created on the fly by typeck whenever a lifetime has no resolution attached to it - while it would be possible to alter the implementation to reuse inference variables based on decisions made early by `resolve_lifetime`, not doing that is more flexible and works better - it can compile all testcases from #38624 by not ending up with `&'static mut (Trait+'static)`.

The ambiguity specifically cannot be an early error, because this is only the "default" (typeck can still pick something better based on the definition of `Trait` and whether it has any lifetime bounds), and having an error at all doesn't help anyone, as we can perfectly infer an appropriate lifetime inside the `fn` body.

**TODO**: write tests for the user-visible changes.

cc @nikomatsakis @arielb1
This commit is contained in:
bors 2017-01-28 06:21:23 +00:00
commit 0f49616a53
39 changed files with 1809 additions and 1866 deletions

View file

@ -327,6 +327,69 @@ struct ListNode {
This works because `Box` is a pointer, so its size is well-known.
"##,
E0106: r##"
This error indicates that a lifetime is missing from a type. If it is an error
inside a function signature, the problem may be with failing to adhere to the
lifetime elision rules (see below).
Here are some simple examples of where you'll run into this error:
```compile_fail,E0106
struct Foo { x: &bool } // error
struct Foo<'a> { x: &'a bool } // correct
enum Bar { A(u8), B(&bool), } // error
enum Bar<'a> { A(u8), B(&'a bool), } // correct
type MyStr = &str; // error
type MyStr<'a> = &'a str; // correct
```
Lifetime elision is a special, limited kind of inference for lifetimes in
function signatures which allows you to leave out lifetimes in certain cases.
For more background on lifetime elision see [the book][book-le].
The lifetime elision rules require that any function signature with an elided
output lifetime must either have
- exactly one input lifetime
- or, multiple input lifetimes, but the function must also be a method with a
`&self` or `&mut self` receiver
In the first case, the output lifetime is inferred to be the same as the unique
input lifetime. In the second case, the lifetime is instead inferred to be the
same as the lifetime on `&self` or `&mut self`.
Here are some examples of elision errors:
```compile_fail,E0106
// error, no input lifetimes
fn foo() -> &str { }
// error, `x` and `y` have distinct lifetimes inferred
fn bar(x: &str, y: &str) -> &str { }
// error, `y`'s lifetime is inferred to be distinct from `x`'s
fn baz<'a>(x: &'a str, y: &str) -> &str { }
```
Here's an example that is currently an error, but may work in a future version
of Rust:
```compile_fail,E0106
struct Foo<'a>(&'a str);
trait Quux { }
impl Quux for Foo { }
```
Lifetime elision in implementation headers was part of the lifetime elision
RFC. It is, however, [currently unimplemented][iss15872].
[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,
E0109: r##"
You tried to give a type parameter to a type which doesn't need it. Erroneous
code example:

View file

@ -301,7 +301,7 @@ pub trait Visitor<'v> : Sized {
fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
fn visit_variant_data(&mut self,
@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v
pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
trait_ref: &'v PolyTraitRef,
_modifier: &'v TraitBoundModifier)
_modifier: TraitBoundModifier)
where V: Visitor<'v>
{
walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyPtr(ref mutable_type) => {
visitor.visit_ty(&mutable_type.ty)
}
TyRptr(ref opt_lifetime, ref mutable_type) => {
walk_list!(visitor, visit_lifetime, opt_lifetime);
TyRptr(ref lifetime, ref mutable_type) => {
visitor.visit_lifetime(lifetime);
visitor.visit_ty(&mutable_type.ty)
}
TyNever => {},
@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
visitor.visit_ty(ty);
visitor.visit_nested_body(length)
}
TyTraitObject(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
}
visitor.visit_lifetime(lifetime);
}
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
match *bound {
TraitTyParamBound(ref typ, ref modifier) => {
TraitTyParamBound(ref typ, modifier) => {
visitor.visit_poly_trait_ref(typ, modifier);
}
RegionTyParamBound(ref lifetime) => {

View file

@ -41,12 +41,12 @@
// in the HIR, especially for multiple identifiers.
use hir;
use hir::map::Definitions;
use hir::map::{Definitions, DefKey};
use hir::map::definitions::DefPathData;
use hir::def_id::{DefIndex, DefId};
use hir::def::{Def, PathResolution};
use session::Session;
use util::nodemap::{NodeMap, FxHashMap};
use util::nodemap::{DefIdMap, NodeMap, FxHashMap};
use std::collections::BTreeMap;
use std::iter;
@ -78,6 +78,8 @@ pub struct LoweringContext<'a> {
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,
type_def_lifetime_params: DefIdMap<usize>,
}
pub trait Resolver {
@ -110,6 +112,7 @@ pub fn lower_crate(sess: &Session,
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
bodies: FxHashMap(),
type_def_lifetime_params: DefIdMap(),
}.lower_crate(krate)
}
@ -123,24 +126,33 @@ enum ParamMode {
impl<'a> LoweringContext<'a> {
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
self.lower_items(c);
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
hir::Crate {
module: module,
attrs: attrs,
span: c.span,
exported_macros: exported_macros,
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
bodies: self.bodies,
/// Full-crate AST visitor that inserts into a fresh
/// `LoweringContext` any information that may be
/// needed from arbitrary locations in the crate.
/// E.g. The number of lifetime generic parameters
/// declared for every type and trait definition.
struct MiscCollector<'lcx, 'interner: 'lcx> {
lctx: &'lcx mut LoweringContext<'interner>,
}
impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> {
fn visit_item(&mut self, item: &'lcx Item) {
match item.node {
ItemKind::Struct(_, ref generics) |
ItemKind::Union(_, ref generics) |
ItemKind::Enum(_, ref generics) |
ItemKind::Ty(_, ref generics) |
ItemKind::Trait(_, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics.lifetimes.len();
self.lctx.type_def_lifetime_params.insert(def_id, count);
}
_ => {}
}
visit::walk_item(self, item);
}
}
}
fn lower_items(&mut self, c: &Crate) {
struct ItemLowerer<'lcx, 'interner: 'lcx> {
lctx: &'lcx mut LoweringContext<'interner>,
}
@ -167,8 +179,23 @@ impl<'a> LoweringContext<'a> {
}
}
let mut item_lowerer = ItemLowerer { lctx: self };
visit::walk_crate(&mut item_lowerer, c);
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c);
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
hir::Crate {
module: module,
attrs: attrs,
span: c.span,
exported_macros: exported_macros,
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
bodies: self.bodies,
}
}
fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
@ -232,6 +259,14 @@ impl<'a> LoweringContext<'a> {
result
}
fn def_key(&mut self, id: DefId) -> DefKey {
if id.is_local() {
self.resolver.definitions().def_key(id.index)
} else {
self.sess.cstore.def_key(id)
}
}
fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
}
@ -279,7 +314,12 @@ impl<'a> LoweringContext<'a> {
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
TyKind::Rptr(ref region, ref mt) => {
hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt))
let span = Span { hi: t.span.lo, ..t.span };
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_lifetime(span)
};
hir::TyRptr(lifetime, self.lower_mt(mt))
}
TyKind::BareFn(ref f) => {
hir::TyBareFn(P(hir::BareFnTy {
@ -297,7 +337,8 @@ impl<'a> LoweringContext<'a> {
return self.lower_ty(ty);
}
TyKind::Path(ref qself, ref path) => {
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit);
return self.ty_path(t.id, t.span, qpath);
}
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
@ -319,7 +360,23 @@ impl<'a> LoweringContext<'a> {
hir::TyTypeof(self.record_body(expr, None))
}
TyKind::TraitObject(ref bounds) => {
hir::TyTraitObject(self.lower_bounds(bounds))
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
Some(self.lower_poly_trait_ref(ty))
}
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
RegionTyParamBound(ref lifetime) => {
lifetime_bound = Some(self.lower_lifetime(lifetime));
None
}
}
}).collect();
let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
self.elided_lifetime(t.span)
});
hir::TyTraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(ref bounds) => {
hir::TyImplTrait(self.lower_bounds(bounds))
@ -377,7 +434,40 @@ impl<'a> LoweringContext<'a> {
}
_ => param_mode
};
self.lower_path_segment(segment, param_mode)
// Figure out if this is a type/trait segment,
// which may need lifetime elision performed.
let parent_def_id = |this: &mut Self, def_id: DefId| {
DefId {
krate: def_id.krate,
index: this.def_key(def_id).parent.expect("missing parent")
}
};
let type_def_id = match resolution.base_def {
Def::AssociatedTy(def_id) if i + 2 == proj_start => {
Some(parent_def_id(self, def_id))
}
Def::Variant(def_id) if i + 1 == proj_start => {
Some(parent_def_id(self, def_id))
}
Def::Struct(def_id) |
Def::Union(def_id) |
Def::Enum(def_id) |
Def::TyAlias(def_id) |
Def::Trait(def_id) if i + 1 == proj_start => Some(def_id),
_ => None
};
let num_lifetimes = type_def_id.map_or(0, |def_id| {
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
return n;
}
assert!(!def_id.is_local());
let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
self.type_def_lifetime_params.insert(def_id, n);
n
});
self.lower_path_segment(p.span, segment, param_mode, num_lifetimes)
}).collect(),
span: p.span,
});
@ -397,7 +487,8 @@ impl<'a> LoweringContext<'a> {
// Otherwise, the base path is an implicit `Self` type path,
// e.g. `Vec` in `Vec::new` or `<I as Iterator>::Item` in
// `<I as Iterator>::Item::default`.
self.ty(p.span, hir::TyPath(hir::QPath::Resolved(qself, path)))
let new_id = self.next_id();
self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path))
};
// Anything after the base path are associated "extensions",
@ -411,7 +502,7 @@ impl<'a> LoweringContext<'a> {
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
let segment = P(self.lower_path_segment(segment, param_mode));
let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0));
let qpath = hir::QPath::TypeRelative(ty, segment);
// It's finished, return the extension of the right node type.
@ -420,7 +511,8 @@ impl<'a> LoweringContext<'a> {
}
// Wrap the associated extension in another type node.
ty = self.ty(p.span, hir::TyPath(qpath));
let new_id = self.next_id();
ty = self.ty_path(new_id, p.span, qpath);
}
// Should've returned in the for loop above.
@ -443,7 +535,7 @@ impl<'a> LoweringContext<'a> {
hir::Path {
def: self.expect_full_def(id),
segments: segments.map(|segment| {
self.lower_path_segment(segment, param_mode)
self.lower_path_segment(p.span, segment, param_mode, 0)
}).chain(name.map(|name| {
hir::PathSegment {
name: name,
@ -464,10 +556,12 @@ impl<'a> LoweringContext<'a> {
}
fn lower_path_segment(&mut self,
path_span: Span,
segment: &PathSegment,
param_mode: ParamMode)
param_mode: ParamMode,
expected_lifetimes: usize)
-> hir::PathSegment {
let parameters = if let Some(ref parameters) = segment.parameters {
let mut parameters = if let Some(ref parameters) = segment.parameters {
match **parameters {
PathParameters::AngleBracketed(ref data) => {
let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
@ -482,6 +576,14 @@ impl<'a> LoweringContext<'a> {
hir::AngleBracketedParameters(data)
};
if let hir::AngleBracketedParameters(ref mut data) = parameters {
if data.lifetimes.is_empty() {
data.lifetimes = (0..expected_lifetimes).map(|_| {
self.elided_lifetime(path_span)
}).collect();
}
}
hir::PathSegment {
name: segment.identifier.name,
parameters: parameters,
@ -628,10 +730,6 @@ impl<'a> LoweringContext<'a> {
lts.iter().map(|l| self.lower_lifetime_def(l)).collect()
}
fn lower_opt_lifetime(&mut self, o_lt: &Option<Lifetime>) -> Option<hir::Lifetime> {
o_lt.as_ref().map(|lt| self.lower_lifetime(lt))
}
fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
let mut add_bounds = NodeMap();
@ -751,8 +849,12 @@ impl<'a> LoweringContext<'a> {
}
fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) {
hir::QPath::Resolved(None, path) => path.and_then(|path| path),
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath)
};
hir::TraitRef {
path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false),
path: path,
ref_id: p.ref_id,
}
}
@ -2269,11 +2371,40 @@ impl<'a> LoweringContext<'a> {
self.expr_block(block, attrs)
}
fn ty(&mut self, span: Span, node: hir::Ty_) -> P<hir::Ty> {
P(hir::Ty {
fn ty_path(&mut self, id: NodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
let mut id = id;
let node = match qpath {
hir::QPath::Resolved(None, path) => {
// Turn trait object paths into `TyTraitObject` instead.
if let Def::Trait(_) = path.def {
let principal = hir::PolyTraitRef {
bound_lifetimes: hir_vec![],
trait_ref: hir::TraitRef {
path: path.and_then(|path| path),
ref_id: id,
},
span,
};
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
id = self.next_id();
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
} else {
hir::TyPath(hir::QPath::Resolved(None, path))
}
}
_ => hir::TyPath(qpath)
};
P(hir::Ty { id, node, span })
}
fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
hir::Lifetime {
id: self.next_id(),
node: node,
span: span,
})
name: keywords::Invalid.name()
}
}
}

View file

@ -77,6 +77,13 @@ pub mod svh;
pub struct Lifetime {
pub id: NodeId,
pub span: Span,
/// Either "'a", referring to a named lifetime definition,
/// or "" (aka keywords::Invalid), for elision placeholders.
///
/// HIR lowering inserts these placeholders in type paths that
/// refer to type definitions needing lifetime parameters,
/// `&T` and `&mut T`, and trait objects without `... + 'a`.
pub name: Name,
}
@ -89,6 +96,12 @@ impl fmt::Debug for Lifetime {
}
}
impl Lifetime {
pub fn is_elided(&self) -> bool {
self.name == keywords::Invalid.name()
}
}
/// A lifetime definition, eg `'a: 'b+'c+'d`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct LifetimeDef {
@ -165,30 +178,6 @@ impl PathParameters {
})
}
pub fn is_empty(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => data.is_empty(),
// Even if the user supplied no types, something like
// `X()` is equivalent to `X<(),()>`.
ParenthesizedParameters(..) => false,
}
}
pub fn has_lifetimes(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(),
ParenthesizedParameters(_) => false,
}
}
pub fn has_types(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => !data.types.is_empty(),
ParenthesizedParameters(..) => true,
}
}
/// Returns the types that the user wrote. Note that these do not necessarily map to the type
/// parameters in the parenthesized case.
pub fn types(&self) -> HirVec<&P<Ty>> {
@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData {
pub bindings: HirVec<TypeBinding>,
}
impl AngleBracketedParameterData {
fn is_empty(&self) -> bool {
self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty()
}
}
/// A path like `Foo(A,B) -> C`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ParenthesizedParameterData {
@ -1208,7 +1191,7 @@ pub enum Ty_ {
/// A raw pointer (`*const T` or `*mut T`)
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
TyRptr(Option<Lifetime>, MutTy),
TyRptr(Lifetime, MutTy),
/// A bare function (e.g. `fn(usize) -> bool`)
TyBareFn(P<BareFnTy>),
/// The never type (`!`)
@ -1222,7 +1205,7 @@ pub enum Ty_ {
TyPath(QPath),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TyTraitObject(TyParamBounds),
TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
/// An `impl Bound1 + Bound2 + Bound3` type
/// where `Bound` is a trait or a lifetime.
TyImplTrait(TyParamBounds),

View file

@ -26,6 +26,7 @@ use syntax_pos::{self, BytePos};
use hir;
use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd};
use std::cell::Cell;
use std::io::{self, Write, Read};
pub enum AnnNode<'a> {
@ -359,9 +360,9 @@ impl<'a> State<'a> {
Ok(())
}
pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> io::Result<()> {
if let Some(l) = *lifetime {
self.print_lifetime(&l)?;
pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
if !lifetime.is_elided() {
self.print_lifetime(lifetime)?;
self.nbsp()?;
}
Ok(())
@ -415,8 +416,21 @@ impl<'a> State<'a> {
hir::TyPath(ref qpath) => {
self.print_qpath(qpath, false)?
}
hir::TyTraitObject(ref bounds) => {
self.print_bounds("", &bounds[..])?;
hir::TyTraitObject(ref bounds, ref lifetime) => {
let mut first = true;
for bound in bounds {
self.nbsp()?;
if first {
first = false;
} else {
self.word_space("+")?;
}
self.print_poly_trait_ref(bound)?;
}
if !lifetime.is_elided() {
self.word_space("+")?;
self.print_lifetime(lifetime)?;
}
}
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
@ -1553,65 +1567,49 @@ impl<'a> State<'a> {
parameters: &hir::PathParameters,
colons_before_params: bool)
-> io::Result<()> {
if parameters.is_empty() {
let infer_types = match *parameters {
hir::AngleBracketedParameters(ref data) => data.infer_types,
hir::ParenthesizedParameters(_) => false
};
// FIXME(eddyb) See the comment below about infer_types.
if !(infer_types && false) {
return Ok(());
}
}
if colons_before_params {
word(&mut self.s, "::")?
}
match *parameters {
hir::AngleBracketedParameters(ref data) => {
word(&mut self.s, "<")?;
let mut comma = false;
for lifetime in &data.lifetimes {
if comma {
self.word_space(",")?
let start = if colons_before_params { "::<" } else { "<" };
let empty = Cell::new(true);
let start_or_comma = |this: &mut Self| {
if empty.get() {
empty.set(false);
word(&mut this.s, start)
} else {
this.word_space(",")
}
};
if !data.lifetimes.iter().all(|lt| lt.is_elided()) {
for lifetime in &data.lifetimes {
start_or_comma(self)?;
self.print_lifetime(lifetime)?;
}
self.print_lifetime(lifetime)?;
comma = true;
}
if !data.types.is_empty() {
if comma {
self.word_space(",")?
}
start_or_comma(self)?;
self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?;
comma = true;
}
// FIXME(eddyb) This would leak into error messages, e.g.:
// "non-exhaustive patterns: `Some::<..>(_)` not covered".
if data.infer_types && false {
if comma {
self.word_space(",")?
}
start_or_comma(self)?;
word(&mut self.s, "..")?;
comma = true;
}
for binding in data.bindings.iter() {
if comma {
self.word_space(",")?
}
start_or_comma(self)?;
self.print_name(binding.name)?;
space(&mut self.s)?;
self.word_space("=")?;
self.print_type(&binding.ty)?;
comma = true;
}
word(&mut self.s, ">")?
if !empty.get() {
word(&mut self.s, ">")?
}
}
hir::ParenthesizedParameters(ref data) => {

View file

@ -29,7 +29,9 @@
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(field_init_shorthand)]
#![feature(libc)]
#![feature(loop_break_value)]
#![feature(nonzero)]
#![feature(pub_restricted)]
#![feature(quote)]

View file

@ -28,6 +28,7 @@ use hir::map as hir_map;
use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
use hir::svh::Svh;
use middle::lang_items;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use ty::{self, Ty, TyCtxt};
use mir::Mir;
use session::Session;
@ -182,6 +183,9 @@ pub trait CrateStore<'tcx> {
-> ty::GenericPredicates<'tcx>;
fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> ty::Generics<'tcx>;
fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
fn item_generics_object_lifetime_defaults(&self, def: DefId)
-> Vec<ObjectLifetimeDefault>;
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
@ -331,6 +335,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
-> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> ty::Generics<'tcx> { bug!("item_generics") }
fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
{ bug!("item_generics_own_param_counts") }
fn item_generics_object_lifetime_defaults(&self, def: DefId)
-> Vec<ObjectLifetimeDefault>
{ bug!("item_generics_object_lifetime_defaults") }
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
{ bug!("trait_def") }

File diff suppressed because it is too large Load diff

View file

@ -592,24 +592,6 @@ pub enum IntVarValue {
UintType(ast::UintTy),
}
/// Default region to use for the bound of objects that are
/// supplied as the value for this type parameter. This is derived
/// from `T:'a` annotations appearing in the type definition. If
/// this is `None`, then the default is inherited from the
/// surrounding context. See RFC #599 for details.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub enum ObjectLifetimeDefault<'tcx> {
/// Require an explicit annotation. Occurs when multiple
/// `T:'a` constraints are found.
Ambiguous,
/// Use the base default, typically 'static, but in a fn body it is a fresh variable
BaseDefault,
/// Use the given region as the default.
Specific(&'tcx Region),
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct TypeParameterDef<'tcx> {
pub name: Name,
@ -617,7 +599,6 @@ pub struct TypeParameterDef<'tcx> {
pub index: u32,
pub default_def_id: DefId, // for use in error reporing about defaults
pub default: Option<Ty<'tcx>>,
pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `T`, asserts data behind the parameter
@ -625,12 +606,11 @@ pub struct TypeParameterDef<'tcx> {
pub pure_wrt_drop: bool,
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct RegionParameterDef<'tcx> {
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct RegionParameterDef {
pub name: Name,
pub def_id: DefId,
pub index: u32,
pub bounds: Vec<&'tcx ty::Region>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `'a`, asserts data of lifetime `'a`
@ -638,7 +618,7 @@ pub struct RegionParameterDef<'tcx> {
pub pure_wrt_drop: bool,
}
impl<'tcx> RegionParameterDef<'tcx> {
impl RegionParameterDef {
pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
ty::EarlyBoundRegion {
index: self.index,
@ -659,7 +639,7 @@ pub struct Generics<'tcx> {
pub parent: Option<DefId>,
pub parent_regions: u32,
pub parent_types: u32,
pub regions: Vec<RegionParameterDef<'tcx>>,
pub regions: Vec<RegionParameterDef>,
pub types: Vec<TypeParameterDef<'tcx>>,
pub has_self: bool,
}
@ -677,7 +657,7 @@ impl<'tcx> Generics<'tcx> {
self.parent_count() + self.own_count()
}
pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> {
pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef {
&self.regions[param.index as usize - self.has_self as usize]
}

View file

@ -353,7 +353,7 @@ macro_rules! CopyImpls {
}
}
CopyImpls! { (), hir::Unsafety, abi::Abi }
CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef }
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
@ -726,52 +726,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
index: self.index,
default: self.default.fold_with(folder),
default_def_id: self.default_def_id,
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
pure_wrt_drop: self.pure_wrt_drop,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.default.visit_with(visitor) ||
self.object_lifetime_default.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::ObjectLifetimeDefault::Ambiguous =>
ty::ObjectLifetimeDefault::Ambiguous,
ty::ObjectLifetimeDefault::BaseDefault =>
ty::ObjectLifetimeDefault::BaseDefault,
ty::ObjectLifetimeDefault::Specific(r) =>
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor),
_ => false,
}
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::RegionParameterDef {
name: self.name,
def_id: self.def_id,
index: self.index,
bounds: self.bounds.fold_with(folder),
pure_wrt_drop: self.pure_wrt_drop,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.bounds.visit_with(visitor)
self.default.visit_with(visitor)
}
}

View file

@ -336,13 +336,12 @@ impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
}
}
impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> {
impl fmt::Debug for ty::RegionParameterDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RegionParameterDef({}, {:?}, {}, {:?})",
write!(f, "RegionParameterDef({}, {:?}, {})",
self.name,
self.def_id,
self.index,
self.bounds)
self.index)
}
}
@ -523,16 +522,6 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
}
}
impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
}
}
}
impl fmt::Display for ty::Region {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if verbose() {

View file

@ -939,12 +939,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option<String> {
// Check wether the argument is an immutable reference
if let hir::TyRptr(opt_lifetime, hir::MutTy {
if let hir::TyRptr(lifetime, hir::MutTy {
mutbl: hir::Mutability::MutImmutable,
ref ty
}) = pty.node {
// Account for existing lifetimes when generating the message
if let Some(lifetime) = opt_lifetime {
if !lifetime.is_elided() {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) {
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
.span_to_snippet(lifetime.span) {

View file

@ -828,7 +828,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
visit::walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) {
fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
debug!("visit_poly_trait_ref: st={:?}", self.st);
SawPolyTraitRef.hash(self.st);
m.hash(self.st);

View file

@ -377,8 +377,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Lint for constants that look like binding identifiers (#7526)
if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
if path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = path.def {
if let Def::Const(..) = path.def {
if path.segments.len() == 1 {
NonUpperCaseGlobals::check_upper_case(cx,
"constant in pattern",
path.segments[0].name,

View file

@ -17,6 +17,7 @@ use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternC
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
use rustc::hir::def::{self, Def};
use rustc::middle::lang_items;
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
@ -110,6 +111,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
self.get_crate_data(def.krate).get_generics(def.index, tcx)
}
fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).generics_own_param_counts(def.index)
}
fn item_generics_object_lifetime_defaults(&self, def: DefId)
-> Vec<ObjectLifetimeDefault> {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
}
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
{
self.dep_graph.read(DepNode::MetaData(def_id));

View file

@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference;
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items;
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
@ -598,7 +599,26 @@ impl<'a, 'tcx> CrateMetadata {
item_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> ty::Generics<'tcx> {
self.entry(item_id).generics.unwrap().decode((self, tcx))
let g = self.entry(item_id).generics.unwrap().decode(self);
ty::Generics {
parent: g.parent,
parent_regions: g.parent_regions,
parent_types: g.parent_types,
regions: g.regions.decode((self, tcx)).collect(),
types: g.types.decode((self, tcx)).collect(),
has_self: g.has_self,
}
}
pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) {
let g = self.entry(item_id).generics.unwrap().decode(self);
(g.regions.len, g.types.len)
}
pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
-> Vec<ObjectLifetimeDefault> {
self.entry(item_id).generics.unwrap().decode(self)
.object_lifetime_defaults.decode(self).collect()
}
pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {

View file

@ -417,9 +417,26 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics<'tcx>> {
fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
let tcx = self.tcx;
self.lazy(tcx.item_generics(def_id))
let g = tcx.item_generics(def_id);
let regions = self.lazy_seq_ref(&g.regions);
let types = self.lazy_seq_ref(&g.types);
let mut object_lifetime_defaults = LazySeq::empty();
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
object_lifetime_defaults = self.lazy_seq_ref(o);
}
}
self.lazy(&Generics {
parent: g.parent,
parent_regions: g.parent_regions,
parent_types: g.parent_types,
regions: regions,
types: types,
has_self: g.has_self,
object_lifetime_defaults: object_lifetime_defaults,
})
}
fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {

View file

@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind};
use rustc::hir::def_id::{DefIndex, DefId};
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
use rustc::middle::lang_items;
use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc_back::PanicStrategy;
@ -213,7 +214,7 @@ pub struct Entry<'tcx> {
pub ty: Option<Lazy<Ty<'tcx>>>,
pub inherent_impls: LazySeq<DefIndex>,
pub variances: LazySeq<ty::Variance>,
pub generics: Option<Lazy<ty::Generics<'tcx>>>,
pub generics: Option<Lazy<Generics<'tcx>>>,
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
@ -247,6 +248,20 @@ pub enum EntryKind<'tcx> {
AssociatedConst(AssociatedContainer),
}
/// A copy of `ty::Generics` which allows lazy decoding of
/// `regions` and `types` (e.g. knowing the number of type
/// and lifetime parameters before `TyCtxt` is created).
#[derive(RustcEncodable, RustcDecodable)]
pub struct Generics<'tcx> {
pub parent: Option<DefId>,
pub parent_regions: u32,
pub parent_types: u32,
pub regions: LazySeq<ty::RegionParameterDef>,
pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
pub has_self: bool,
pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
}
#[derive(RustcEncodable, RustcDecodable)]
pub struct ModData {
pub reexports: LazySeq<def::Export>,

View file

@ -144,6 +144,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
TyKind::TraitObject(ref bounds) => {
let mut any_lifetime_bounds = false;
for bound in bounds {
if let RegionTyParamBound(ref lifetime) = *bound {
if any_lifetime_bounds {
span_err!(self.session, lifetime.span, E0226,
"only a single explicit lifetime bound is permitted");
break;
}
any_lifetime_bounds = true;
}
}
self.no_questions_in_bounds(bounds, "trait object types", false);
}
TyKind::ImplTrait(ref bounds) => {

View file

@ -244,6 +244,7 @@ match 5u32 {
}
register_diagnostics! {
E0226, // only a single explicit lifetime bound is permitted
E0472, // asm! is unsupported on this target
E0561, // patterns aren't allowed in function pointer types
E0571, // `break` with a value in a non-`loop`-loop

File diff suppressed because it is too large Load diff

View file

@ -80,7 +80,7 @@ pub use self::Expectation::*;
pub use self::compare_method::{compare_impl_method, compare_const_impl};
use self::TupleArgumentsFlag::*;
use astconv::{AstConv, ast_region_to_region};
use astconv::AstConv;
use dep_graph::DepNode;
use fmt_macros::{Parser, Piece, Position};
use hir::def::{Def, CtorKind};
@ -97,7 +97,6 @@ use rustc::ty::adjustment;
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
use session::{Session, CompileResult};
use CrateCtxt;
use TypeAndSubsts;
@ -1410,6 +1409,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
Ok(r)
}
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-> Option<&'tcx ty::Region> {
let v = match def {
Some(def) => infer::EarlyBoundRegion(span, def.name),
None => infer::MiscVariable(span)
};
Some(self.next_region_var(v))
}
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
self.next_ty_var(TypeVariableOrigin::TypeInference(span))
}
@ -1450,30 +1458,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
}
}
impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
// RFC #599 specifies that object lifetime defaults take
// precedence over other defaults. But within a fn body we
// don't have a *default* region, rather we use inference to
// find the *correct* region, which is strictly more general
// (and anyway, within a fn body the right region may not even
// be something the user can write explicitly, since it might
// be some expression).
*self.next_region_var(infer::MiscVariable(span))
}
fn anon_regions(&self, span: Span, count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
Ok((0..count).map(|_| {
*self.next_region_var(infer::MiscVariable(span))
}).collect())
}
}
/// Controls whether the arguments are tupled. This is used for the call
/// operator.
///
@ -1830,7 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
let t = AstConv::ast_ty_to_ty(self, self, ast_t);
let t = AstConv::ast_ty_to_ty(self, ast_t);
self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
t
}
@ -3974,7 +3958,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match *qpath {
hir::QPath::Resolved(ref maybe_qself, ref path) => {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, node_id, true);
let ty = AstConv::def_to_ty(self, opt_self_ty, path, true);
(path.def, ty)
}
hir::QPath::TypeRelative(ref qself, ref segment) => {
@ -4406,10 +4390,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
None => &[]
};
if let Some(ast_lifetime) = lifetimes.get(i) {
ast_region_to_region(self.tcx, ast_lifetime)
if let Some(lifetime) = lifetimes.get(i) {
AstConv::ast_region_to_region(self, lifetime, Some(def))
} else {
self.region_var_for_def(span, def)
self.re_infer(span, Some(def)).unwrap()
}
}, |def, substs| {
let mut i = def.index as usize;

View file

@ -57,7 +57,7 @@ There are some shortcomings in this design:
*/
use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds};
use astconv::{AstConv, Bounds};
use lint;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
@ -68,10 +68,9 @@ use rustc::ty::subst::Substs;
use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
use rscope::*;
use rustc::dep_graph::DepNode;
use util::common::{ErrorReported, MemoizationMap};
use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
use util::nodemap::{NodeMap, FxHashMap};
use CrateCtxt;
use rustc_const_math::ConstInt;
@ -373,8 +372,8 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
}
impl<'a,'tcx> ItemCtxt<'a,'tcx> {
fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> {
AstConv::ast_ty_to_ty(self, rs, ast_ty)
fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
AstConv::ast_ty_to_ty(self, ast_ty)
}
}
@ -437,6 +436,11 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
None
}
fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
-> Option<&'tcx ty::Region> {
None
}
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
struct_span_err!(
self.tcx().sess,
@ -626,7 +630,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
field: &hir::StructField,
ty_f: &'tcx ty::FieldDef)
{
let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty);
let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
let def_id = ccx.tcx.hir.local_def_id(field.id);
@ -636,11 +640,8 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: AssociatedItemContainer,
id: ast::NodeId,
sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
body: Option<hir::BodyId>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
let def_id = ccx.tcx.hir.local_def_id(id);
let ty_generics = generics_of_def_id(ccx, def_id);
@ -648,18 +649,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let ty_generic_predicates =
ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
let anon_scope = match container {
ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
TraitContainer(_) => None
};
let assoc_item = ccx.tcx.associated_item(def_id);
let self_value_ty = if assoc_item.method_has_self_argument {
Some(untransformed_rcvr_ty)
} else {
None
};
let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
sig, self_value_ty, body, anon_scope);
let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
sig.unsafety, sig.abi, &sig.decl);
let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
ccx.tcx.hir.span(id), def_id);
@ -765,7 +756,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
let trait_ref =
AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
&ExplicitRscope,
ast_trait_ref,
tcx.mk_self_type());
@ -787,12 +777,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
debug!("convert: impl_bounds={:?}", ty_predicates);
let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty);
let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
tcx.item_types.borrow_mut().insert(def_id, selfty);
let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
&ExplicitRscope,
ast_trait_ref,
selfty)
});
@ -858,8 +847,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
hir::TraitItemKind::Const(ref ty, _) => {
let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, &ty);
let ty = ccx.icx(&trait_predicates).to_ty(&ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, TraitContainer(trait_def_id),
trait_item.id, ty);
@ -870,20 +858,14 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
generics_of_def_id(ccx, type_def_id);
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
|ty| ccx.icx(&trait_predicates).to_ty(&ty)
});
convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
}
hir::TraitItemKind::Method(ref sig, ref method) => {
let body = match *method {
hir::TraitMethod::Required(_) => None,
hir::TraitMethod::Provided(body) => Some(body)
};
convert_method(ccx, TraitContainer(trait_def_id),
trait_item.id, sig, tcx.mk_self_type(),
body, &trait_predicates);
hir::TraitItemKind::Method(ref sig, _) => {
convert_method(ccx, trait_item.id, sig, &trait_predicates);
}
}
}
@ -896,14 +878,12 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
let impl_predicates = tcx.item_predicates(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let impl_self_ty = tcx.item_type(impl_def_id);
match impl_item.node {
hir::ImplItemKind::Const(ref ty, _) => {
let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&impl_predicates)
.to_ty(&ExplicitRscope, &ty);
let ty = ccx.icx(&impl_predicates).to_ty(&ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, ImplContainer(impl_def_id),
impl_item.id, ty);
@ -918,15 +898,13 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
"associated types are not allowed in inherent impls");
}
let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty);
let typ = ccx.icx(&impl_predicates).to_ty(ty);
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
hir::ImplItemKind::Method(ref sig, body) => {
convert_method(ccx, ImplContainer(impl_def_id),
impl_item.id, sig, impl_self_ty,
Some(body), &impl_predicates);
hir::ImplItemKind::Method(ref sig, _) => {
convert_method(ccx, impl_item.id, sig, &impl_predicates);
}
}
}
@ -1197,7 +1175,6 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
self_param_ty,
bounds,
SizedByDefault::No,
None,
item.span);
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
@ -1334,7 +1311,6 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item)
assoc_ty,
bounds,
SizedByDefault::Yes,
None,
trait_item.span);
bounds.predicates(ccx.tcx, assoc_ty).into_iter()
@ -1429,7 +1405,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
def_id: tcx.hir.local_def_id(param_id),
default_def_id: tcx.hir.local_def_id(parent),
default: None,
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
pure_wrt_drop: false,
};
tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
@ -1471,9 +1446,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
name: l.lifetime.name,
index: own_start + i as u32,
def_id: tcx.hir.local_def_id(l.lifetime.id),
bounds: l.bounds.iter().map(|l| {
ast_region_to_region(tcx, l)
}).collect(),
pure_wrt_drop: l.pure_wrt_drop,
}
}).collect::<Vec<_>>();
@ -1482,7 +1454,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let type_start = own_start + regions.len() as u32;
let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
let i = type_start + i as u32;
get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
});
let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
@ -1497,24 +1469,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
def_id: def_id,
default_def_id: parent_def_id.unwrap(),
default: None,
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
pure_wrt_drop: false,
}));
});
}
// Debugging aid.
if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
let object_lifetime_default_reprs: String =
types.iter().map(|t| {
match t.object_lifetime_default {
ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
d => format!("{:?}", d),
}
}).collect::<Vec<String>>().join(",");
tcx.sess.span_err(tcx.hir.span(node_id), &object_lifetime_default_reprs);
}
tcx.alloc_generics(ty::Generics {
parent: parent_def_id,
parent_regions: parent_regions,
@ -1545,16 +1504,15 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
NodeItem(item) => {
match item.node {
ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
ccx.icx(&()).to_ty(&t)
}
ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
body, Some(AnonTypeScope::new(def_id)));
ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
ccx.tcx.mk_fn_def(def_id, substs, tofd)
}
ItemTy(ref t, ref generics) => {
ccx.icx(generics).to_ty(&ExplicitRscope, &t)
ccx.icx(generics).to_ty(&t)
}
ItemEnum(ref ei, ref generics) => {
let def = convert_enum_def(ccx, item, ei);
@ -1595,7 +1553,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fn_decl, generics, abi)
}
ForeignItemStatic(ref t, _) => {
ccx.icx(&()).to_ty(&ExplicitRscope, t)
ccx.icx(&()).to_ty(t)
}
}
}
@ -1765,7 +1723,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
name: param.lifetime.name
}));
for bound in &param.bounds {
let bound_region = ast_region_to_region(ccx.tcx, bound);
let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
predicates.push(outlives.to_predicate());
}
@ -1781,7 +1739,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
param_ty,
&param.bounds,
SizedByDefault::Yes,
None,
param.span);
predicates.extend(bounds.predicates(ccx.tcx, param_ty));
}
@ -1792,7 +1749,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
match predicate {
&hir::WherePredicate::BoundPredicate(ref bound_pred) => {
let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
&ExplicitRscope,
&bound_pred.bounded_ty);
for bound in bound_pred.bounds.iter() {
@ -1803,7 +1759,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let trait_ref =
AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
ast_generics)),
&ExplicitRscope,
poly_trait_ref,
ty,
&mut projections);
@ -1816,7 +1771,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
&hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
let region = ast_region_to_region(tcx, lifetime);
let region = AstConv::ast_region_to_region(&ccx.icx(&()),
lifetime,
None);
let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
predicates.push(ty::Predicate::TypeOutlives(pred))
}
@ -1825,9 +1782,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
&hir::WherePredicate::RegionPredicate(ref region_pred) => {
let r1 = ast_region_to_region(tcx, &region_pred.lifetime);
let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), &region_pred.lifetime, None);
for bound in &region_pred.bounds {
let r2 = ast_region_to_region(tcx, bound);
let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
predicates.push(ty::Predicate::RegionOutlives(pred))
}
@ -1846,7 +1803,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
ast_generics: &hir::Generics,
index: u32,
param: &hir::TyParam,
allow_defaults: bool)
@ -1859,11 +1815,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
let default =
param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def));
let object_lifetime_default =
compute_object_lifetime_default(ccx, param.id,
&param.bounds, &ast_generics.where_clause);
param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
let parent = tcx.hir.get_parent(param.id);
@ -1884,7 +1836,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
def_id: ccx.tcx.hir.local_def_id(param.id),
default_def_id: ccx.tcx.hir.local_def_id(parent),
default: default,
object_lifetime_default: object_lifetime_default,
pure_wrt_drop: param.pure_wrt_drop,
};
@ -1899,75 +1850,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
def
}
/// Scan the bounds and where-clauses on a parameter to extract bounds
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
/// This runs as part of computing the minimal type scheme, so we
/// intentionally avoid just asking astconv to convert all the where
/// clauses into a `ty::Predicate`. This is because that could induce
/// artificial cycles.
fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
param_id: ast::NodeId,
param_bounds: &[hir::TyParamBound],
where_clause: &hir::WhereClause)
-> ty::ObjectLifetimeDefault<'tcx>
{
let inline_bounds = from_bounds(ccx, param_bounds);
let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
let all_bounds: FxHashSet<_> = inline_bounds.into_iter()
.chain(where_bounds)
.collect();
return if all_bounds.len() > 1 {
ty::ObjectLifetimeDefault::Ambiguous
} else if all_bounds.len() == 0 {
ty::ObjectLifetimeDefault::BaseDefault
} else {
ty::ObjectLifetimeDefault::Specific(
all_bounds.into_iter().next().unwrap())
};
fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
bounds: &[hir::TyParamBound])
-> Vec<&'tcx ty::Region>
{
bounds.iter()
.filter_map(|bound| {
match *bound {
hir::TraitTyParamBound(..) =>
None,
hir::RegionTyParamBound(ref lifetime) =>
Some(ast_region_to_region(ccx.tcx, lifetime)),
}
})
.collect()
}
fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
param_id: ast::NodeId,
predicates: &[hir::WherePredicate])
-> Vec<&'tcx ty::Region>
{
predicates.iter()
.flat_map(|predicate| {
match *predicate {
hir::WherePredicate::BoundPredicate(ref data) => {
if data.bound_lifetimes.is_empty() &&
is_param(ccx.tcx, &data.bounded_ty, param_id)
{
from_bounds(ccx, &data.bounds).into_iter()
} else {
Vec::new().into_iter()
}
}
hir::WherePredicate::RegionPredicate(..) |
hir::WherePredicate::EqPredicate(..) => {
Vec::new().into_iter()
}
}
})
.collect()
}
}
pub enum SizedByDefault { Yes, No, }
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
@ -1977,28 +1859,33 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[hir::TyParamBound],
sized_by_default: SizedByDefault,
anon_scope: Option<AnonTypeScope>,
span: Span)
-> Bounds<'tcx>
{
let tcx = astconv.tcx();
let PartitionedBounds {
trait_bounds,
region_bounds
} = partition_bounds(&ast_bounds);
let mut region_bounds = vec![];
let mut trait_bounds = vec![];
for ast_bound in ast_bounds {
match *ast_bound {
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
trait_bounds.push(b);
}
hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
hir::RegionTyParamBound(ref l) => {
region_bounds.push(l);
}
}
}
let mut projection_bounds = vec![];
let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope);
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
astconv.instantiate_poly_trait_ref(&rscope,
bound,
astconv.instantiate_poly_trait_ref(bound,
param_ty,
&mut projection_bounds)
}).collect();
let region_bounds = region_bounds.into_iter().map(|r| {
ast_region_to_region(tcx, r)
astconv.ast_region_to_region(r, None)
}).collect();
trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
@ -2030,8 +1917,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
match *bound {
hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => {
let mut projections = Vec::new();
let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope,
tr,
let pred = astconv.instantiate_poly_trait_ref(tr,
param_ty,
&mut projections);
projections.into_iter()
@ -2040,7 +1926,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
.collect()
}
hir::RegionTyParamBound(ref lifetime) => {
let region = ast_region_to_region(astconv.tcx(), lifetime);
let region = astconv.ast_region_to_region(lifetime, None);
let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region));
vec![ty::Predicate::TypeOutlives(pred)]
}
@ -2058,18 +1944,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
abi: abi::Abi)
-> Ty<'tcx>
{
let rb = BindingRscope::new();
let input_tys = decl.inputs
.iter()
.map(|a| AstConv::ty_of_arg(&ccx.icx(ast_generics), &rb, a, None))
.collect::<Vec<_>>();
let output = match decl.output {
hir::Return(ref ty) =>
AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty),
hir::DefaultReturn(..) =>
ccx.tcx.mk_nil(),
};
let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl);
// feature gate SIMD types in FFI, since I (huonw) am not sure the
// ABIs are handled at all correctly.
@ -2085,27 +1960,23 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
.emit();
}
};
for (input, ty) in decl.inputs.iter().zip(&input_tys) {
for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) {
check(&input, ty)
}
if let hir::Return(ref ty) = decl.output {
check(&ty, output)
check(&ty, *fty.sig.output().skip_binder())
}
}
let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap();
let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id);
ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
abi: abi,
unsafety: hir::Unsafety::Unsafe,
sig: ty::Binder(ccx.tcx.mk_fn_sig(input_tys.into_iter(), output, decl.variadic)),
}))
ccx.tcx.mk_fn_def(def_id, substs, fty)
}
pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
span: Span,
def_id: DefId)
-> &'tcx Substs<'tcx> {
fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
span: Span,
def_id: DefId)
-> &'tcx Substs<'tcx> {
let tcx = astconv.tcx();
// FIXME(eddyb) Do this request from Substs::for_item in librustc.
if let Err(ErrorReported) = astconv.get_generics(span, def_id) {

View file

@ -1412,85 +1412,19 @@ fn main() {
```
"##,
E0106: r##"
This error indicates that a lifetime is missing from a type. If it is an error
inside a function signature, the problem may be with failing to adhere to the
lifetime elision rules (see below).
Here are some simple examples of where you'll run into this error:
```compile_fail,E0106
struct Foo { x: &bool } // error
struct Foo<'a> { x: &'a bool } // correct
enum Bar { A(u8), B(&bool), } // error
enum Bar<'a> { A(u8), B(&'a bool), } // correct
type MyStr = &str; // error
type MyStr<'a> = &'a str; // correct
```
Lifetime elision is a special, limited kind of inference for lifetimes in
function signatures which allows you to leave out lifetimes in certain cases.
For more background on lifetime elision see [the book][book-le].
The lifetime elision rules require that any function signature with an elided
output lifetime must either have
- exactly one input lifetime
- or, multiple input lifetimes, but the function must also be a method with a
`&self` or `&mut self` receiver
In the first case, the output lifetime is inferred to be the same as the unique
input lifetime. In the second case, the lifetime is instead inferred to be the
same as the lifetime on `&self` or `&mut self`.
Here are some examples of elision errors:
```compile_fail,E0106
// error, no input lifetimes
fn foo() -> &str { }
// error, `x` and `y` have distinct lifetimes inferred
fn bar(x: &str, y: &str) -> &str { }
// error, `y`'s lifetime is inferred to be distinct from `x`'s
fn baz<'a>(x: &'a str, y: &str) -> &str { }
```
[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision
"##,
E0107: r##"
This error means that an incorrect number of lifetime parameters were provided
for a type (like a struct or enum) or trait.
Some basic examples include:
for a type (like a struct or enum) or trait:
```compile_fail,E0107
struct Foo<'a>(&'a str);
struct Foo<'a, 'b>(&'a str, &'b str);
enum Bar { A, B, C }
struct Baz<'a> {
foo: Foo, // error: expected 1, found 0
foo: Foo<'a>, // error: expected 2, found 1
bar: Bar<'a>, // error: expected 0, found 1
}
```
Here's an example that is currently an error, but may work in a future version
of Rust:
```compile_fail,E0107
struct Foo<'a>(&'a str);
trait Quux { }
impl Quux for Foo { } // error: expected 1, found 0
```
Lifetime elision in implementation headers was part of the lifetime elision
RFC. It is, however, [currently unimplemented][iss15872].
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,
E0116: r##"
@ -4162,7 +4096,6 @@ register_diagnostics! {
// E0222, // Error code E0045 (variadic function must have C calling
// convention) duplicate
E0224, // at least one non-builtin train is required for an object type
E0226, // only a single explicit lifetime bound is permitted
E0227, // ambiguous lifetime bound, explicit lifetime bound required
E0228, // explicit lifetime bound required
E0231, // only named substitution parameters are allowed

View file

@ -77,6 +77,7 @@ This API is completely unstable and subject to change.
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(loop_break_value)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
@ -126,7 +127,6 @@ pub mod diagnostics;
pub mod check;
pub mod check_unused;
mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;

View file

@ -1,393 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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.
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::subst::Substs;
use astconv::AstConv;
use std::cell::Cell;
use syntax_pos::Span;
#[derive(Clone)]
pub struct ElisionFailureInfo {
/// Where we can find the argument pattern.
pub parent: Option<hir::BodyId>,
/// The index of the argument in the original definition.
pub index: usize,
pub lifetime_count: usize,
pub have_bound_regions: bool
}
pub type ElidedLifetime = Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
/// Defines strategies for handling regions that are omitted. For
/// example, if one writes the type `&Foo`, then the lifetime of
/// this reference has been omitted. When converting this
/// type, the generic functions in astconv will invoke `anon_regions`
/// on the provided region-scope to decide how to translate this
/// omitted region.
///
/// It is not always legal to omit regions, therefore `anon_regions`
/// can return `Err(())` to indicate that this is not a scope in which
/// regions can legally be omitted.
pub trait RegionScope {
fn anon_regions(&self,
span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>;
/// If an object omits any explicit lifetime bound, and none can
/// be derived from the object traits, what should we use? If
/// `None` is returned, an explicit annotation is required.
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
/// The "base" default is the initial default for a scope. This is
/// 'static except for in fn bodies, where it is a fresh inference
/// variable. You shouldn't call this except for as part of
/// computing `object_lifetime_default` (in particular, in legacy
/// modes, it may not be relevant).
fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
/// If this scope allows anonymized types, return the generics in
/// scope, that anonymized types will close over. For example,
/// if you have a function like:
///
/// fn foo<'a, T>() -> impl Trait { ... }
///
/// then, for the rscope that is used when handling the return type,
/// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`,
/// on which `.fresh_substs(...)` can be used to obtain identity
/// Substs for `'a` and `T`, to track them in `TyAnon`. This property
/// is controlled by the region scope because it's fine-grained enough
/// to allow restriction of anonymized types to the syntactical extent
/// of a function's return type.
fn anon_type_scope(&self) -> Option<AnonTypeScope> {
None
}
}
#[derive(Copy, Clone)]
pub struct AnonTypeScope {
enclosing_item: DefId
}
impl<'gcx: 'tcx, 'tcx> AnonTypeScope {
pub fn new(enclosing_item: DefId) -> AnonTypeScope {
AnonTypeScope {
enclosing_item: enclosing_item
}
}
pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span)
-> &'tcx Substs<'tcx> {
use collect::mk_item_substs;
mk_item_substs(astconv, span, self.enclosing_item)
}
}
/// A scope wrapper which optionally allows anonymized types.
#[derive(Copy, Clone)]
pub struct MaybeWithAnonTypes<R> {
base_scope: R,
anon_scope: Option<AnonTypeScope>
}
impl<R: RegionScope> MaybeWithAnonTypes<R> {
pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope>) -> Self {
MaybeWithAnonTypes {
base_scope: base_scope,
anon_scope: anon_scope
}
}
}
impl<R: RegionScope> RegionScope for MaybeWithAnonTypes<R> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
self.base_scope.object_lifetime_default(span)
}
fn anon_regions(&self,
span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
self.base_scope.anon_regions(span, count)
}
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
self.base_scope.base_object_lifetime_default(span)
}
fn anon_type_scope(&self) -> Option<AnonTypeScope> {
self.anon_scope
}
}
// A scope in which all regions must be explicitly named. This is used
// for types that appear in structs and so on.
#[derive(Copy, Clone)]
pub struct ExplicitRscope;
impl RegionScope for ExplicitRscope {
fn anon_regions(&self,
_span: Span,
_count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
Err(None)
}
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
ty::ReStatic
}
}
// Same as `ExplicitRscope`, but provides some extra information for diagnostics
pub struct UnelidableRscope(Option<Vec<ElisionFailureInfo>>);
impl UnelidableRscope {
pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope {
UnelidableRscope(v)
}
}
impl RegionScope for UnelidableRscope {
fn anon_regions(&self,
_span: Span,
_count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
let UnelidableRscope(ref v) = *self;
Err(v.clone())
}
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
ty::ReStatic
}
}
// A scope in which omitted anonymous region defaults to
// `default`. This is used after the `->` in function signatures. The
// latter use may go away. Note that object-lifetime defaults work a
// bit differently, as specified in RFC #599.
pub struct ElidableRscope {
default: ty::Region,
}
impl ElidableRscope {
pub fn new(r: ty::Region) -> ElidableRscope {
ElidableRscope { default: r }
}
}
impl RegionScope for ElidableRscope {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over
// lifetime elision.
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
ty::ReStatic
}
fn anon_regions(&self,
_span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{
Ok(vec![self.default; count])
}
}
/// A scope that behaves as an ElidabeRscope with a `'static` default region
/// that should also warn if the `static_in_const` feature is unset.
#[derive(Copy, Clone)]
pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> {
/// create a new StaticRscope from a reference to the `TyCtxt`
pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self {
StaticRscope { tcx: tcx }
}
}
impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> {
fn anon_regions(&self,
span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
if !self.tcx.sess.features.borrow().static_in_const {
self.tcx
.sess
.struct_span_err(span,
"this needs a `'static` lifetime or the \
`static_in_const` feature, see #35897")
.emit();
}
Ok(vec![ty::ReStatic; count])
}
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
ty::ReStatic
}
}
/// A scope in which we generate anonymous, late-bound regions for
/// omitted regions. This occurs in function signatures.
pub struct BindingRscope {
anon_bindings: Cell<u32>,
}
impl BindingRscope {
pub fn new() -> BindingRscope {
BindingRscope {
anon_bindings: Cell::new(0),
}
}
fn next_region(&self) -> ty::Region {
let idx = self.anon_bindings.get();
self.anon_bindings.set(idx + 1);
ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx))
}
}
impl RegionScope for BindingRscope {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over the
// binding defaults in a fn signature.
Some(self.base_object_lifetime_default(span))
}
fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
ty::ReStatic
}
fn anon_regions(&self,
_: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{
Ok((0..count).map(|_| self.next_region()).collect())
}
}
/// A scope which overrides the default object lifetime but has no other effect.
pub struct ObjectLifetimeDefaultRscope<'r> {
base_scope: &'r (RegionScope+'r),
default: ty::ObjectLifetimeDefault<'r>,
}
impl<'r> ObjectLifetimeDefaultRscope<'r> {
pub fn new(base_scope: &'r (RegionScope+'r),
default: ty::ObjectLifetimeDefault<'r>)
-> ObjectLifetimeDefaultRscope<'r>
{
ObjectLifetimeDefaultRscope {
base_scope: base_scope,
default: default,
}
}
}
impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
match self.default {
ty::ObjectLifetimeDefault::Ambiguous =>
None,
ty::ObjectLifetimeDefault::BaseDefault =>
// NB: This behavior changed in Rust 1.3.
Some(self.base_object_lifetime_default(span)),
ty::ObjectLifetimeDefault::Specific(r) =>
Some(*r),
}
}
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
self.base_scope.base_object_lifetime_default(span)
}
fn anon_regions(&self,
span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{
self.base_scope.anon_regions(span, count)
}
fn anon_type_scope(&self) -> Option<AnonTypeScope> {
self.base_scope.anon_type_scope()
}
}
/// A scope which simply shifts the Debruijn index of other scopes
/// to account for binding levels.
pub struct ShiftedRscope<'r> {
base_scope: &'r (RegionScope+'r)
}
impl<'r> ShiftedRscope<'r> {
pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> {
ShiftedRscope { base_scope: base_scope }
}
}
impl<'r> RegionScope for ShiftedRscope<'r> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
self.base_scope.object_lifetime_default(span)
.map(|r| ty::fold::shift_region(r, 1))
}
fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
}
fn anon_regions(&self,
span: Span,
count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
{
match self.base_scope.anon_regions(span, count) {
Ok(mut v) => {
for r in &mut v {
*r = ty::fold::shift_region(*r, 1);
}
Ok(v)
}
Err(errs) => {
Err(errs)
}
}
}
fn anon_type_scope(&self) -> Option<AnonTypeScope> {
self.base_scope.anon_type_scope()
}
}

View file

@ -154,7 +154,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
let tcx = self.terms_cx.tcx;
assert!(is_lifetime(&tcx.hir, param_id));
match tcx.named_region_map.defs.get(&param_id) {
Some(&rl::DefEarlyBoundRegion(_, lifetime_decl_id)) => lifetime_decl_id,
Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id,
Some(_) => bug!("should not encounter non early-bound cases"),
// The lookup should only fail when `param_id` is

View file

@ -28,7 +28,7 @@ use syntax::symbol::keywords;
use syntax_pos::{self, DUMMY_SP, Pos};
use rustc::middle::privacy::AccessLevels;
use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::middle::resolve_lifetime as rl;
use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@ -765,9 +765,9 @@ impl Clean<Lifetime> for hir::Lifetime {
fn clean(&self, cx: &DocContext) -> Lifetime {
let def = cx.tcx.named_region_map.defs.get(&self.id).cloned();
match def {
Some(DefEarlyBoundRegion(_, node_id)) |
Some(DefLateBoundRegion(_, node_id)) |
Some(DefFreeRegion(_, node_id)) => {
Some(rl::Region::EarlyBound(_, node_id)) |
Some(rl::Region::LateBound(_, node_id)) |
Some(rl::Region::Free(_, node_id)) => {
if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
return lt;
}
@ -794,7 +794,7 @@ impl Clean<Lifetime> for hir::LifetimeDef {
}
}
impl<'tcx> Clean<Lifetime> for ty::RegionParameterDef<'tcx> {
impl Clean<Lifetime> for ty::RegionParameterDef {
fn clean(&self, _: &DocContext) -> Lifetime {
Lifetime(self.name.to_string())
}
@ -970,11 +970,6 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
Some(tp.clean(cx))
}
}).collect::<Vec<_>>();
let stripped_lifetimes = gens.regions.iter().map(|rp| {
let mut srp = rp.clone();
srp.bounds = Vec::new();
srp.clean(cx)
}).collect::<Vec<_>>();
let mut where_predicates = preds.predicates.to_vec().clean(cx);
@ -1017,7 +1012,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
Generics {
type_params: simplify::ty_params(stripped_typarams),
lifetimes: stripped_lifetimes,
lifetimes: gens.regions.clean(cx),
where_predicates: simplify::where_clauses(cx, where_predicates),
}
}
@ -1688,9 +1683,15 @@ impl Clean<Type> for hir::Ty {
match self.node {
TyNever => Never,
TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
TyRptr(ref l, ref m) => {
let lifetime = if l.is_elided() {
None
} else {
Some(l.clean(cx))
};
BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)}
}
TySlice(ref ty) => Vector(box ty.clean(cx)),
TyArray(ref ty, length) => {
use rustc_const_eval::eval_length;
@ -1729,7 +1730,9 @@ impl Clean<Type> for hir::Ty {
for (i, lt_param) in generics.lifetimes.iter().enumerate() {
if let Some(lt) = provided_params.lifetimes().get(i).cloned()
.cloned() {
lt_substs.insert(lt_param.lifetime.id, lt.clean(cx));
if !lt.is_elided() {
lt_substs.insert(lt_param.lifetime.id, lt.clean(cx));
}
}
}
return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
@ -1768,20 +1771,20 @@ impl Clean<Type> for hir::Ty {
trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
}
}
TyTraitObject(ref bounds) => {
let lhs_ty = bounds[0].clean(cx);
match lhs_ty {
TraitBound(poly_trait, ..) => {
match poly_trait.trait_ {
ResolvedPath { path, typarams: None, did, is_generic } => {
ResolvedPath {
path: path,
typarams: Some(bounds[1..].clean(cx)),
did: did,
is_generic: is_generic,
}
}
_ => Infer // shouldn't happen
TyTraitObject(ref bounds, ref lifetime) => {
match bounds[0].clean(cx).trait_ {
ResolvedPath { path, typarams: None, did, is_generic } => {
let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
}).collect();
if !lifetime.is_elided() {
bounds.push(RegionBound(lifetime.clean(cx)));
}
ResolvedPath {
path: path,
typarams: Some(bounds),
did: did,
is_generic: is_generic,
}
}
_ => Infer // shouldn't happen
@ -2242,7 +2245,11 @@ impl Clean<PathParameters> for hir::PathParameters {
match *self {
hir::AngleBracketedParameters(ref data) => {
PathParameters::AngleBracketed {
lifetimes: data.lifetimes.clean(cx),
lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) {
vec![]
} else {
data.lifetimes.clean(cx)
},
types: data.types.clean(cx),
bindings: data.bindings.clean(cx)
}

View file

@ -23,5 +23,17 @@ type MyStr = &str;
//~^ ERROR E0106
//~| NOTE expected lifetime parameter
struct Baz<'a>(&'a str);
struct Buzz<'a, 'b>(&'a str, &'b str);
struct Quux {
baz: Baz,
//~^ ERROR E0106
//~| expected lifetime parameter
buzz: Buzz,
//~^ ERROR E0106
//~| expected 2 lifetime parameters
}
fn main() {
}

View file

@ -18,9 +18,6 @@ enum Bar {
}
struct Baz<'a, 'b, 'c> {
foo: Foo,
//~^ ERROR E0107
//~| expected 1 lifetime parameter
buzz: Buzz<'a>,
//~^ ERROR E0107
//~| expected 2 lifetime parameters

View file

@ -22,10 +22,11 @@ struct SomeStruct<I : for<'x> Foo<&'x isize>> {
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
}
struct AnotherStruct<I : for<'x> Foo<&'x isize>> {
field: <I as Foo<&isize>>::A
//~^ ERROR missing lifetime specifier
}
// FIXME(eddyb) This one doesn't even compile because of the unsupported syntax.
// struct AnotherStruct<I : for<'x> Foo<&'x isize>> {
// field: <I as for<'y> Foo<&'y isize>>::A
// }
struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> {
field: <I as Foo<&'a isize>>::A

View file

@ -26,9 +26,9 @@ trait LazyToString {
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
}
// Note that the following impl doesn't error, because the trait is invalid.
impl LazyToString for String {
fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String {
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
|| self.clone()
}
}

View file

@ -38,4 +38,28 @@ fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier
panic!()
}
// Cases which used to work but now don't.
type StaticStr = &'static str; // hides 'static
trait WithLifetime<'a> {
type Output; // can hide 'a
}
// This worked because the type of the first argument contains
// 'static, although StaticStr doesn't even have parameters.
fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier
//~^ HELP this function's return type contains a borrowed value
//~| HELP consider giving it an explicit bounded or 'static lifetime
panic!()
}
// This worked because the compiler resolved the argument type
// to <T as WithLifetime<'a>>::Output which has the hidden 'a.
fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
//~^ ERROR missing lifetime specifier
//~| HELP this function's return type contains a borrowed value
//~| HELP consider giving it an explicit bounded or 'static lifetime
panic!()
}
fn main() {}

View file

@ -18,7 +18,7 @@ trait SomeTrait { }
// Bounds on object types:
struct Foo<'a,'b,'c> {
struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used
// All of these are ok, because we can derive exactly one bound:
a: Box<IsStatic>,
b: Box<Is<'static>>,
@ -28,7 +28,9 @@ struct Foo<'a,'b,'c> {
f: Box<SomeTrait>, // OK, defaults to 'static due to RFC 599.
g: Box<SomeTrait+'a>,
z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
z: Box<Is<'a>+'b+'c>,
//~^ ERROR only a single explicit lifetime bound is permitted
//~| ERROR lifetime bound not satisfied
}
fn test<

View file

@ -15,8 +15,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
}
// the boundaries of elision
static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8);
static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
//~^ ERROR missing lifetime specifier [E0106]
&(non_elidable as fn(&u8, &u8) -> &u8);
//~^ ERROR missing lifetime specifier [E0106]
struct SomeStruct<'x, 'y, 'z: 'x> {
foo: &'x Foo<'z>,

View file

@ -38,9 +38,9 @@ fn test<'a,'b>() {
}
fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) {
//~^ ERROR wrong number of lifetime parameters: expected 1, found 0
// Here, the omitted lifetimes are expanded to distinct things.
same_type(x, y) //~ ERROR cannot infer
//~^ ERROR cannot infer
same_type(x, y)
}
fn main() { }

View file

@ -10,7 +10,7 @@
fn f() where u8 = u16 {}
//~^ ERROR equality constraints are not yet supported in where clauses
fn g() where for<'a> &(u8,) == u16, {}
fn g() where for<'a> &'static (u8,) == u16, {}
//~^ ERROR equality constraints are not yet supported in where clauses
fn main() {}

View file

@ -15,6 +15,8 @@
#![allow(dead_code)]
use std::fmt::Display;
trait Test {
fn foo(&self) { }
}
@ -23,6 +25,11 @@ struct Ref<'a,T:'a+?Sized> {
r: &'a T
}
struct Ref2<'a,'b,T:'a+'b+?Sized> {
a: &'a T,
b: &'b T
}
struct SomeStruct<'a> {
t: Ref<'a,Test>,
u: Ref<'a,Test+'a>,
@ -44,6 +51,17 @@ fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn e<'a>(_: Ref<'a, Display+'static>) {}
fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {}
fn main() {
// Inside a function body, we can just infer all
// lifetimes, to allow Ref<'tmp, Display+'static>
// and Ref2<'tmp, 'tmp, Display+'static>.
let x = &0 as &(Display+'static);
let r: Ref<Display> = Ref { r: x };
let r2: Ref2<Display> = Ref2 { a: x, b: x };
e(r);
g(r2);
}

View file

@ -15,6 +15,8 @@
#![allow(dead_code)]
use std::fmt::Display;
trait Test {
fn foo(&self) { }
}
@ -40,6 +42,10 @@ fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn e<'a>(_: &'a (Display+'static)) {}
fn main() {
// Inside a function body, we can just infer both
// lifetimes, to allow &'tmp (Display+'static).
e(&0 as &Display);
}