Auto merge of #55229 - nikomatsakis:issue-54692-closure-signatures, r=MatthewJasper

enforce user annotations in closure signatures

Not *quite* ready yet but I'm opening anyway. Still have to finish running tests locally.

Fixes #54692
Fixes #54124

r? @matthewjasper
This commit is contained in:
bors 2018-10-23 17:44:19 +00:00
commit f99911a4a0
24 changed files with 321 additions and 101 deletions

View File

@ -50,7 +50,8 @@ use ty::query;
use ty::steal::Steal;
use ty::BindingMode;
use ty::CanonicalTy;
use util::nodemap::{DefIdSet, ItemLocalMap};
use ty::CanonicalPolyFnSig;
use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
use util::nodemap::{FxHashMap, FxHashSet};
use smallvec::SmallVec;
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
@ -344,10 +345,6 @@ pub struct TypeckTables<'tcx> {
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
field_indices: ItemLocalMap<usize>,
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
/// typeck::check::fn_ctxt for details.
@ -359,6 +356,14 @@ pub struct TypeckTables<'tcx> {
/// other items.
node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
/// Stores the canonicalized types provided by the user. See also
/// `AscribeUserType` statement in MIR.
pub user_provided_sigs: DefIdMap<CanonicalPolyFnSig<'tcx>>,
/// Stores the substitutions that the user explicitly gave (if any)
/// attached to `id`. These will not include any inferred
/// values. The canonical form is used to capture things like `_`
@ -442,6 +447,7 @@ impl<'tcx> TypeckTables<'tcx> {
type_dependent_defs: ItemLocalMap(),
field_indices: ItemLocalMap(),
user_provided_tys: ItemLocalMap(),
user_provided_sigs: Default::default(),
node_types: ItemLocalMap(),
node_substs: ItemLocalMap(),
user_substs: ItemLocalMap(),
@ -748,6 +754,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
ref type_dependent_defs,
ref field_indices,
ref user_provided_tys,
ref user_provided_sigs,
ref node_types,
ref node_substs,
ref user_substs,
@ -771,6 +778,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
type_dependent_defs.hash_stable(hcx, hasher);
field_indices.hash_stable(hcx, hasher);
user_provided_tys.hash_stable(hcx, hasher);
user_provided_sigs.hash_stable(hcx, hasher);
node_types.hash_stable(hcx, hasher);
node_substs.hash_stable(hcx, hasher);
user_substs.hash_stable(hcx, hasher);

View File

@ -64,7 +64,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
use hir;
pub use self::sty::{Binder, BoundTy, BoundTyIndex, DebruijnIndex, INNERMOST};
pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig};
pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TyKind, PolyTraitRef};

View File

@ -11,7 +11,7 @@
//! This module contains TyKind and its major components
use hir::def_id::DefId;
use infer::canonical::Canonical;
use mir::interpret::ConstValue;
use middle::region;
use polonius_engine::Atom;
@ -980,6 +980,9 @@ impl<'tcx> PolyFnSig<'tcx> {
}
}
pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct ParamTy {
pub idx: u32,

View File

@ -1208,6 +1208,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// to report the error. This gives better error messages
// in some cases.
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
return; // continuing to iterate just reports more errors than necessary
}
}

View File

@ -18,6 +18,7 @@
//! contain revealed `impl Trait` values).
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::infer::LateBoundRegionConversionTime;
use rustc::mir::*;
use rustc::ty::Ty;
@ -36,9 +37,47 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let (&normalized_output_ty, normalized_input_tys) =
normalized_inputs_and_output.split_last().unwrap();
// If the user explicitly annotated the input types, extract
// those.
//
// e.g. `|x: FxHashMap<_, &'static u32>| ...`
let user_provided_sig;
if !self.tcx().is_closure(self.mir_def_id) {
user_provided_sig = None;
} else {
let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
None => None,
Some(user_provided_poly_sig) => {
// Instantiate the canonicalized variables from
// user-provided signature (e.g. the `_` in the code
// above) with fresh variables.
let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
mir.span,
&user_provided_poly_sig,
);
// Replace the bound items in the fn sig with fresh
// variables, so that they represent the view from
// "inside" the closure.
Some(
self.infcx
.replace_late_bound_regions_with_fresh_var(
mir.span,
LateBoundRegionConversionTime::FnCall,
&poly_sig,
)
.0,
)
}
}
};
// Equate expected input tys with those in the MIR.
let argument_locals = (1..).map(Local::new);
for (&normalized_input_ty, local) in normalized_input_tys.iter().zip(argument_locals) {
for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
// In MIR, argument N is stored in local N+1.
let local = Local::new(argument_index + 1);
debug!(
"equate_inputs_and_outputs: normalized_input_ty = {:?}",
normalized_input_ty
@ -53,6 +92,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
}
if let Some(user_provided_sig) = user_provided_sig {
for (&user_provided_input_ty, argument_index) in
user_provided_sig.inputs().iter().zip(0..)
{
// In MIR, closures begin an implicit `self`, so
// argument N is stored in local N+2.
let local = Local::new(argument_index + 2);
let mir_input_ty = mir.local_decls[local].ty;
let mir_input_span = mir.local_decls[local].source_info.span;
// If the user explicitly annotated the input types, enforce those.
let user_provided_input_ty =
self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
self.equate_normalized_input_or_output(
user_provided_input_ty,
mir_input_ty,
mir_input_span,
);
}
}
assert!(
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
|| mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
@ -83,6 +143,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
terr
);
};
// If the user explicitly annotated the output types, enforce those.
if let Some(user_provided_sig) = user_provided_sig {
let user_provided_output_ty = user_provided_sig.output();
let user_provided_output_ty =
self.normalize(user_provided_output_ty, Locations::All(output_span));
self.equate_normalized_input_or_output(
user_provided_output_ty,
mir_output_ty,
output_span,
);
}
}
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {

View File

@ -1033,6 +1033,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
assert!(!impl_self_ty.has_infer_types());
self.eq_types(self_ty, impl_self_ty, locations, category)?;
self.prove_predicate(
ty::Predicate::WellFormed(impl_self_ty),
locations,
category,
);
}
// Prove the predicates coming along with `def_id`.
@ -1070,11 +1076,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
/// particularly necessary -- we'll do it lazilly as we process
/// the value anyway -- but in some specific cases it is useful to
/// normalize so we can suppress duplicate error messages.
fn fold_to_region_vid<T>(
&self,
value: T
) -> T
where T: TypeFoldable<'tcx>
fn fold_to_region_vid<T>(&self, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
if let Some(borrowck_context) = &self.borrowck_context {
self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
@ -1210,12 +1214,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// though.
let category = match *place {
Place::Local(RETURN_PLACE) => if let Some(BorrowCheckContext {
universal_regions: UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _),
..
},
universal_regions:
UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _),
..
},
..
}) = self.borrowck_context {
}) = self.borrowck_context
{
if tcx.is_static(*def_id).is_some() {
ConstraintCategory::UseAsStatic
} else {
@ -1223,7 +1229,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
} else {
ConstraintCategory::Return
}
},
Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
@ -1510,12 +1516,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let category = match *dest {
Place::Local(RETURN_PLACE) => {
if let Some(BorrowCheckContext {
universal_regions: UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _),
..
},
universal_regions:
UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _),
..
},
..
}) = self.borrowck_context {
}) = self.borrowck_context
{
if tcx.is_static(*def_id).is_some() {
ConstraintCategory::UseAsStatic
} else {
@ -1524,7 +1532,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
} else {
ConstraintCategory::Return
}
},
}
Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
@ -1582,12 +1590,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
} else {
ConstraintCategory::Boring
};
if let Err(terr) = self.sub_types(
op_arg_ty,
fn_arg,
term_location.to_locations(),
category,
) {
if let Err(terr) =
self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category)
{
span_mirbug!(
self,
term,

View File

@ -377,7 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
) -> ClosureSignatures<'tcx> {
debug!("sig_of_closure_no_expectation()");
let bound_sig = self.supplied_sig_of_closure(decl);
let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl);
self.closure_sigs(expr_def_id, body, bound_sig)
}
@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Along the way, it also writes out entries for types that the user
// wrote into our tables, which are then later used by the privacy
// check.
match self.check_supplied_sig_against_expectation(decl, &closure_sigs) {
match self.check_supplied_sig_against_expectation(expr_def_id, decl, &closure_sigs) {
Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body),
}
@ -521,6 +521,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// strategy.
fn check_supplied_sig_against_expectation(
&self,
expr_def_id: DefId,
decl: &hir::FnDecl,
expected_sigs: &ClosureSignatures<'tcx>,
) -> InferResult<'tcx, ()> {
@ -528,7 +529,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
//
// (See comment on `sig_of_closure_with_expectation` for the
// meaning of these letters.)
let supplied_sig = self.supplied_sig_of_closure(decl);
let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl);
debug!(
"check_supplied_sig_against_expectation: supplied_sig={:?}",
@ -598,7 +599,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// If there is no expected signature, then we will convert the
/// types that the user gave into a signature.
fn supplied_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> {
///
/// Also, record this closure signature for later.
fn supplied_sig_of_closure(
&self,
expr_def_id: DefId,
decl: &hir::FnDecl,
) -> ty::PolyFnSig<'tcx> {
let astconv: &dyn AstConv = self;
// First, convert the types that the user supplied (if any).
@ -618,6 +625,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("supplied_sig_of_closure: result={:?}", result);
let c_result = self.inh.infcx.canonicalize_response(&result);
self.tables.borrow_mut().user_provided_sigs.insert(
expr_def_id,
c_result,
);
result
}

View File

@ -52,6 +52,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_cast_types();
wbcx.visit_free_region_map();
wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs();
let used_trait_imports = mem::replace(
&mut self.tables.borrow_mut().used_trait_imports,
@ -388,6 +389,27 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}
fn visit_user_provided_sigs(&mut self) {
let fcx_tables = self.fcx.tables.borrow();
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
for (&def_id, c_sig) in fcx_tables.user_provided_sigs.iter() {
let c_sig = if let Some(c_sig) = self.tcx().lift_to_global(c_sig) {
c_sig
} else {
span_bug!(
self.fcx.tcx.hir.span_if_local(def_id).unwrap(),
"writeback: `{:?}` missing from the global type context",
c_sig
);
};
self.tables
.user_provided_sigs
.insert(def_id, c_sig.clone());
}
}
fn visit_opaque_types(&mut self, span: Span) {
for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();

View File

@ -95,7 +95,7 @@ pub fn add_type_ascription_to_parameter() {
}
#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody")]
#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_ascription_to_parameter() {
let closure = |x: u32| x + 1u32;

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-compare-mode-nll
struct Foo<'a, 'b: 'a>(&'a &'b ());
impl<'a, 'b> Foo<'a, 'b> {

View File

@ -1,16 +1,16 @@
error[E0478]: lifetime bound not satisfied
--> $DIR/issue-28848.rs:22:5
--> $DIR/issue-28848.rs:20:5
|
LL | Foo::<'a, 'b>::xmute(u) //~ ERROR lifetime bound not satisfied
| ^^^^^^^^^^^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime 'b as defined on the function body at 21:16
--> $DIR/issue-28848.rs:21:16
note: lifetime parameter instantiated with the lifetime 'b as defined on the function body at 19:16
--> $DIR/issue-28848.rs:19:16
|
LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
| ^^
note: but lifetime parameter must outlive the lifetime 'a as defined on the function body at 21:12
--> $DIR/issue-28848.rs:21:12
note: but lifetime parameter must outlive the lifetime 'a as defined on the function body at 19:12
--> $DIR/issue-28848.rs:19:12
|
LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
| ^^

View File

@ -47,7 +47,6 @@ fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
//~^ ERROR unsatisfied lifetime constraints
});
}

View File

@ -7,7 +7,6 @@ LL | | //~^ ERROR borrowed data escapes outside of function
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
@ -44,21 +43,9 @@ LL | | //~^ ERROR borrowed data escapes outside of function
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |______^ `cell_a` escapes the function body here
error: unsatisfied lifetime constraints
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:49:9
|
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0521`.

View File

@ -47,9 +47,9 @@ fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u3
fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
//~^ ERROR borrowed data escapes outside of function
// Only works if 'x: 'y:
demand_y(x, y, x.get())
//~^ ERROR unsatisfied lifetime constraints
});
}

View File

@ -4,9 +4,9 @@ note: External requirements
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| _______________________________________________^
LL | | //~^ ERROR borrowed data escapes outside of function
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |_____^
|
@ -25,7 +25,7 @@ note: No external requirements
LL | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
LL | | // Only works if 'x: 'y:
LL | |
... |
LL | | });
LL | | }
@ -40,23 +40,12 @@ LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
| ------ `cell_a` is a reference that is only valid in the function body
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR borrowed data escapes outside of function
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | });
| |______^ `cell_a` escapes the function body here
error: unsatisfied lifetime constraints
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:51:9
|
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0521`.

View File

@ -0,0 +1,43 @@
// Copyright 2017 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.
#![feature(nll)]
// Test that we enforce user-provided type annotations on closures.
fn foo<'a>() {
// Here `x` is free in the closure sig:
|x: &'a i32| -> &'static i32 {
return x; //~ ERROR unsatisfied lifetime constraints
};
}
fn foo1() {
// Here `x` is bound in the closure sig:
|x: &i32| -> &'static i32 {
return x; //~ ERROR unsatisfied lifetime constraints
};
}
fn bar<'a>() {
// Here `x` is free in the closure sig:
|x: &'a i32, b: fn(&'static i32)| {
b(x); //~ ERROR unsatisfied lifetime constraints
};
}
fn bar1() {
// Here `x` is bound in the closure sig:
|x: &i32, b: fn(&'static i32)| {
b(x); //~ ERROR borrowed data escapes outside of closure
};
}
fn main() { }

View File

@ -0,0 +1,37 @@
error: unsatisfied lifetime constraints
--> $DIR/closure-substs.rs:18:16
|
LL | fn foo<'a>() {
| -- lifetime `'a` defined here
...
LL | return x; //~ ERROR unsatisfied lifetime constraints
| ^ returning this value requires that `'a` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/closure-substs.rs:25:16
|
LL | |x: &i32| -> &'static i32 {
| - let's call the lifetime of this reference `'1`
LL | return x; //~ ERROR unsatisfied lifetime constraints
| ^ returning this value requires that `'1` must outlive `'static`
error: unsatisfied lifetime constraints
--> $DIR/closure-substs.rs:32:9
|
LL | fn bar<'a>() {
| -- lifetime `'a` defined here
...
LL | b(x); //~ ERROR unsatisfied lifetime constraints
| ^^^^ argument requires that `'a` must outlive `'static`
error[E0521]: borrowed data escapes outside of closure
--> $DIR/closure-substs.rs:39:9
|
LL | |x: &i32, b: fn(&'static i32)| {
| - `x` is a reference that is only valid in the closure body
LL | b(x); //~ ERROR borrowed data escapes outside of closure
| ^^^^ `x` escapes the closure body here
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0521`.

View File

@ -0,0 +1,9 @@
#![feature(nll)]
fn test<'a>() {
let _:fn(&()) = |_:&'a ()| {};
}
fn main() {
test();
}

View File

@ -0,0 +1,20 @@
error: unsatisfied lifetime constraints
--> $DIR/issue-54124.rs:4:22
|
LL | fn test<'a>() {
| -- lifetime `'a` defined here
LL | let _:fn(&()) = |_:&'a ()| {};
| ^ - let's call the lifetime of this reference `'1`
| |
| requires that `'1` must outlive `'a`
error: unsatisfied lifetime constraints
--> $DIR/issue-54124.rs:4:22
|
LL | fn test<'a>() {
| -- lifetime `'a` defined here
LL | let _:fn(&()) = |_:&'a ()| {};
| ^ requires that `'a` must outlive `'static`
error: aborting due to 2 previous errors

View File

@ -0,0 +1,25 @@
// Copyright 2017 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.
#![feature(nll)]
struct Foo<'a, 'b: 'a>(&'a &'b ());
impl<'a, 'b> Foo<'a, 'b> {
fn xmute(a: &'b ()) -> &'a () {
unreachable!()
}
}
pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
Foo::xmute(u) //~ ERROR unsatisfied lifetime constraints
}
fn main() {}

View File

@ -0,0 +1,12 @@
error: unsatisfied lifetime constraints
--> $DIR/wf-self-type.rs:22:5
|
LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | Foo::xmute(u) //~ ERROR unsatisfied lifetime constraints
| ^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
error: aborting due to previous error

View File

@ -20,7 +20,7 @@ LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of
| ^^^^^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `v`
--> $DIR/regions-static-bound.rs:27:5
--> $DIR/regions-static-bound.rs:26:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`

View File

@ -15,7 +15,7 @@ LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of
| ^^^^^^^^^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `v`
--> $DIR/regions-static-bound.rs:27:5
--> $DIR/regions-static-bound.rs:26:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
@ -23,27 +23,6 @@ LL | fn error(u: &(), v: &()) {
LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
| ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
error: unsatisfied lifetime constraints
--> $DIR/regions-static-bound.rs:24:5
|
LL | fn error(u: &(), v: &()) {
| - - let's call the lifetime of this reference `'2`
| |
| let's call the lifetime of this reference `'1`
LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
| ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
error: unsatisfied lifetime constraints
--> $DIR/regions-static-bound.rs:27:5
|
LL | fn error(u: &(), v: &()) {
| - - let's call the lifetime of this reference `'1`
| |
| let's call the lifetime of this reference `'2`
...
LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
| ^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
error: aborting due to 5 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0621`.

View File

@ -23,10 +23,8 @@ fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
fn error(u: &(), v: &()) {
static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
//[nll]~^ ERROR explicit lifetime required in the type of `u` [E0621]
//[nll]~| ERROR unsatisfied lifetime constraints
static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
//[nll]~^ ERROR explicit lifetime required in the type of `v` [E0621]
//[nll]~| ERROR unsatisfied lifetime constraints
}
fn main() {}