From 167b460961b4c3c127c0fc8782012043c8cf97af Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 19 Oct 2018 06:25:12 -0400 Subject: [PATCH 01/10] add a table to track user-provided signatures --- src/librustc/ty/context.rs | 30 ++++++++++++++++++++++---- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 5 ++++- src/librustc_typeck/check/writeback.rs | 28 ++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 9f718cea58f5e..46c99f79eced0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -50,6 +50,7 @@ use ty::query; use ty::steal::Steal; use ty::BindingMode; use ty::CanonicalTy; +use ty::CanonicalPolyFnSig; use util::nodemap::{DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use smallvec::SmallVec; @@ -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, - /// Stores the canonicalized types provided by the user. See also - /// `AscribeUserType` statement in MIR. - user_provided_tys: ItemLocalMap>, - /// 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>, + + /// Stores the canonicalized types provided by the user. See also + /// `AscribeUserType` statement in MIR. + user_provided_sigs: ItemLocalMap>, + /// 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(), @@ -513,6 +519,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn user_provided_sigs(&self) -> LocalTableInContext<'_, CanonicalPolyFnSig<'tcx>> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.user_provided_sigs + } + } + + pub fn user_provided_sigs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalPolyFnSig<'tcx>> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.user_provided_sigs + } + } + pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> { LocalTableInContext { local_id_root: self.local_id_root, @@ -748,6 +768,7 @@ impl<'a, 'gcx> HashStable> 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 +792,7 @@ impl<'a, 'gcx> HashStable> 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); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5602ce479c8dc..bb9346f2f468d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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}; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8289158387015..cd9679c876355 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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>>; + + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 40f5d27356c7b..d81b600d9bef4 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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,33 @@ 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); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); + + for (&local_id, c_sig) in fcx_tables.user_provided_sigs().iter() { + let hir_id = hir::HirId { + owner: common_local_id_root.index, + local_id, + }; + + let c_sig = if let Some(c_sig) = self.tcx().lift_to_global(c_sig) { + c_sig + } else { + span_bug!( + hir_id.to_span(&self.fcx.tcx), + "writeback: `{:?}` missing from the global type context", + c_sig + ); + }; + + self.tables + .user_provided_sigs_mut() + .insert(hir_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(); From a8f3d6dafcecd85941a04958cac38fe05573945e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 19 Oct 2018 17:19:29 -0400 Subject: [PATCH 02/10] convert user-provided signatures into def-id --- src/librustc/ty/context.rs | 18 ++---------------- src/librustc_typeck/check/writeback.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 46c99f79eced0..c60471c285dcb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -51,7 +51,7 @@ use ty::steal::Steal; use ty::BindingMode; use ty::CanonicalTy; use ty::CanonicalPolyFnSig; -use util::nodemap::{DefIdSet, ItemLocalMap}; +use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, @@ -362,7 +362,7 @@ pub struct TypeckTables<'tcx> { /// Stores the canonicalized types provided by the user. See also /// `AscribeUserType` statement in MIR. - user_provided_sigs: ItemLocalMap>, + pub user_provided_sigs: DefIdMap>, /// Stores the substitutions that the user explicitly gave (if any) /// attached to `id`. These will not include any inferred @@ -519,20 +519,6 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn user_provided_sigs(&self) -> LocalTableInContext<'_, CanonicalPolyFnSig<'tcx>> { - LocalTableInContext { - local_id_root: self.local_id_root, - data: &self.user_provided_sigs - } - } - - pub fn user_provided_sigs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalPolyFnSig<'tcx>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.user_provided_sigs - } - } - pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> { LocalTableInContext { local_id_root: self.local_id_root, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d81b600d9bef4..d968bf222aa09 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -392,27 +392,21 @@ 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); - let common_local_id_root = fcx_tables.local_id_root.unwrap(); - - for (&local_id, c_sig) in fcx_tables.user_provided_sigs().iter() { - let hir_id = hir::HirId { - owner: common_local_id_root.index, - local_id, - }; + 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!( - hir_id.to_span(&self.fcx.tcx), + self.fcx.tcx.hir.span_if_local(def_id).unwrap(), "writeback: `{:?}` missing from the global type context", c_sig ); }; self.tables - .user_provided_sigs_mut() - .insert(hir_id, c_sig.clone()); + .user_provided_sigs + .insert(def_id, c_sig.clone()); } } From e0871ed318e2e6706f81c98cc348bcb99e78b4bf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 19 Oct 2018 17:24:24 -0400 Subject: [PATCH 03/10] record supplied sig of closure --- src/librustc_typeck/check/closure.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 940fa4d3916bc..3f4d187813d5d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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 } From 3a178805397e07be4cd8506f34dbdb17abc8426d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Oct 2018 08:38:16 -0400 Subject: [PATCH 04/10] start enforcing closure types --- .../nll/type_check/input_output.rs | 76 ++++++++++++++++++- .../ui/nll/user-annotations/closure-substs.rs | 29 +++++++ .../user-annotations/closure-substs.stderr | 42 ++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/closure-substs.rs create mode 100644 src/test/ui/nll/user-annotations/closure-substs.stderr diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index a4665984d3e0b..ab4ee3a4ad0e5 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -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) { diff --git a/src/test/ui/nll/user-annotations/closure-substs.rs b/src/test/ui/nll/user-annotations/closure-substs.rs new file mode 100644 index 0000000000000..0a22390fc714a --- /dev/null +++ b/src/test/ui/nll/user-annotations/closure-substs.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , 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>() { + |x: &'a i32| -> &'static i32 { + return x; //~ ERROR + }; +} + +fn bar<'a>() { + |x: &i32, b: fn(&'static i32)| { + b(x); //~ ERROR + //~^ ERROR borrowed data escapes outside of closure + //~| ERROR unsatisfied lifetime constraints + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr new file mode 100644 index 0000000000000..97f6e594de5ee --- /dev/null +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -0,0 +1,42 @@ +error: unsatisfied lifetime constraints + --> $DIR/closure-substs.rs:17:16 + | +LL | fn foo<'a>() { + | -- lifetime `'a` defined here +LL | |x: &'a i32| -> &'static i32 { +LL | return x; //~ ERROR + | ^ returning this value requires that `'a` must outlive `'static` + +error: borrowed data escapes outside of closure + --> $DIR/closure-substs.rs:23:9 + | +LL | |x: &i32, b: fn(&'static i32)| { + | - `x` is a reference that is only valid in the closure body +LL | b(x); //~ ERROR + | ^^^^ `x` escapes the closure body here + +error: borrowed data escapes outside of closure + --> $DIR/closure-substs.rs:23:9 + | +LL | |x: &i32, b: fn(&'static i32)| { + | - - `b` is declared here, outside of the closure body + | | + | `x` is a reference that is only valid in the closure body +LL | b(x); //~ ERROR + | ^^^^ `x` escapes the closure body here + +error: unsatisfied lifetime constraints + --> $DIR/closure-substs.rs:23:9 + | +LL | |x: &i32, b: fn(&'static i32)| { + | ------------------------------ + | | | + | | let's call the lifetime of this reference `'1` + | lifetime `'2` represents this closure's body +LL | b(x); //~ ERROR + | ^^^^ argument requires that `'1` must outlive `'2` + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: aborting due to 4 previous errors + From dbbdce51dc6e3173e1f736e952915a2c22e92928 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Oct 2018 15:00:57 -0400 Subject: [PATCH 05/10] add regression test for #54124 Fixes #54124 --- .../ui/nll/user-annotations/issue-54124.rs | 9 +++++++++ .../nll/user-annotations/issue-54124.stderr | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/issue-54124.rs create mode 100644 src/test/ui/nll/user-annotations/issue-54124.stderr diff --git a/src/test/ui/nll/user-annotations/issue-54124.rs b/src/test/ui/nll/user-annotations/issue-54124.rs new file mode 100644 index 0000000000000..8cdd390540a09 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-54124.rs @@ -0,0 +1,9 @@ +#![feature(nll)] + +fn test<'a>() { + let _:fn(&()) = |_:&'a ()| {}; +} + +fn main() { + test(); +} diff --git a/src/test/ui/nll/user-annotations/issue-54124.stderr b/src/test/ui/nll/user-annotations/issue-54124.stderr new file mode 100644 index 0000000000000..df5e4b0447ce7 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-54124.stderr @@ -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 + From 0afccbb654cfe98ac426b32ccd19ce069e7138a7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Oct 2018 18:26:27 -0400 Subject: [PATCH 06/10] fix incremental test --- src/test/incremental/hashes/closure_expressions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index 839e0ca8e01ae..8469f0aa6645d 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -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; From 2921fbaaa8f85c0306d5592973f924a74d356f9a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 Oct 2018 09:19:33 -0400 Subject: [PATCH 07/10] flesh out closure-substs test --- .../ui/nll/user-annotations/closure-substs.rs | 20 ++++++- .../user-annotations/closure-substs.stderr | 54 ++++++++++++++++--- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/test/ui/nll/user-annotations/closure-substs.rs b/src/test/ui/nll/user-annotations/closure-substs.rs index 0a22390fc714a..7dd2d4113bb48 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.rs +++ b/src/test/ui/nll/user-annotations/closure-substs.rs @@ -13,12 +13,30 @@ // 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 + 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 + //~^ ERROR unsatisfied lifetime constraints + //~| 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 //~^ ERROR borrowed data escapes outside of closure diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index 97f6e594de5ee..126a66b80592c 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -1,14 +1,54 @@ error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:17:16 + --> $DIR/closure-substs.rs:18:16 | LL | fn foo<'a>() { | -- lifetime `'a` defined here -LL | |x: &'a i32| -> &'static i32 { -LL | return x; //~ ERROR +... +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:25:16 + | +LL | |x: &i32| -> &'static i32 { + | - - return type of closure is &'2 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 `'2` + +error: unsatisfied lifetime constraints + --> $DIR/closure-substs.rs:25:16 + | +LL | |x: &i32| -> &'static i32 { + | ------------------------- + | | | + | | let's call the lifetime of this reference `'1` + | lifetime `'2` represents this closure's body +LL | return x; //~ ERROR unsatisfied lifetime constraints + | ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure + +error: unsatisfied lifetime constraints + --> $DIR/closure-substs.rs:34:9 + | +LL | fn bar<'a>() { + | -- lifetime `'a` defined here +... +LL | b(x); //~ ERROR unsatisfied lifetime constraints + | ^^^^ argument requires that `'a` must outlive `'static` + error: borrowed data escapes outside of closure - --> $DIR/closure-substs.rs:23:9 + --> $DIR/closure-substs.rs:41:9 | LL | |x: &i32, b: fn(&'static i32)| { | - `x` is a reference that is only valid in the closure body @@ -16,7 +56,7 @@ LL | b(x); //~ ERROR | ^^^^ `x` escapes the closure body here error: borrowed data escapes outside of closure - --> $DIR/closure-substs.rs:23:9 + --> $DIR/closure-substs.rs:41:9 | LL | |x: &i32, b: fn(&'static i32)| { | - - `b` is declared here, outside of the closure body @@ -26,7 +66,7 @@ LL | b(x); //~ ERROR | ^^^^ `x` escapes the closure body here error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:23:9 + --> $DIR/closure-substs.rs:41:9 | LL | |x: &i32, b: fn(&'static i32)| { | ------------------------------ @@ -38,5 +78,5 @@ LL | b(x); //~ ERROR | = note: closure implements `Fn`, so references to captured variables can't escape the closure -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors From 64b5599352545e390ead3da4f14c3a1ffaba50d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 Oct 2018 11:20:17 -0400 Subject: [PATCH 08/10] stop reporting "unsatisfied lifetime bounds" errors after the first In particular, after the first for a given region variable. This suppresses a lot of duplicate errors. --- .../borrow_check/nll/region_infer/mod.rs | 1 + ...approximated-shorter-to-static-no-bound.rs | 1 - ...oximated-shorter-to-static-no-bound.stderr | 15 +---- ...roximated-shorter-to-static-wrong-bound.rs | 2 +- ...mated-shorter-to-static-wrong-bound.stderr | 19 ++----- .../ui/nll/user-annotations/closure-substs.rs | 6 +- .../user-annotations/closure-substs.stderr | 57 ++----------------- .../ui/regions/regions-static-bound.ll.stderr | 2 +- .../regions/regions-static-bound.nll.stderr | 25 +------- src/test/ui/regions/regions-static-bound.rs | 2 - 10 files changed, 17 insertions(+), 113 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 5ed25406da4e6..50fd4afcd7eca 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -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 } } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs index 49b6258164013..4bef6cf8cd160 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs @@ -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 }); } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index a5435cc65caa0..f22dbdba934e8 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -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`. diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs index 0181792cbdcff..05e9818b91e56 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs @@ -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 }); } diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 35692414081ac..2b1cb5a30ceda 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -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`. diff --git a/src/test/ui/nll/user-annotations/closure-substs.rs b/src/test/ui/nll/user-annotations/closure-substs.rs index 7dd2d4113bb48..77c7315fa665c 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.rs +++ b/src/test/ui/nll/user-annotations/closure-substs.rs @@ -23,8 +23,6 @@ fn foo1() { // Here `x` is bound in the closure sig: |x: &i32| -> &'static i32 { return x; //~ ERROR unsatisfied lifetime constraints - //~^ ERROR unsatisfied lifetime constraints - //~| ERROR unsatisfied lifetime constraints }; } @@ -38,9 +36,7 @@ fn bar<'a>() { fn bar1() { // Here `x` is bound in the closure sig: |x: &i32, b: fn(&'static i32)| { - b(x); //~ ERROR - //~^ ERROR borrowed data escapes outside of closure - //~| ERROR unsatisfied lifetime constraints + b(x); //~ ERROR borrowed data escapes outside of closure }; } diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index 126a66b80592c..c69d514d9e636 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -16,30 +16,7 @@ LL | return x; //~ ERROR unsatisfied lifetime constraints | ^ returning this value requires that `'1` must outlive `'static` error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:25:16 - | -LL | |x: &i32| -> &'static i32 { - | - - return type of closure is &'2 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 `'2` - -error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:25:16 - | -LL | |x: &i32| -> &'static i32 { - | ------------------------- - | | | - | | let's call the lifetime of this reference `'1` - | lifetime `'2` represents this closure's body -LL | return x; //~ ERROR unsatisfied lifetime constraints - | ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - | - = note: closure implements `Fn`, so references to captured variables can't escape the closure - -error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:34:9 + --> $DIR/closure-substs.rs:32:9 | LL | fn bar<'a>() { | -- lifetime `'a` defined here @@ -47,36 +24,14 @@ LL | fn bar<'a>() { LL | b(x); //~ ERROR unsatisfied lifetime constraints | ^^^^ argument requires that `'a` must outlive `'static` -error: borrowed data escapes outside of closure - --> $DIR/closure-substs.rs:41:9 +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 - | ^^^^ `x` escapes the closure body here - -error: borrowed data escapes outside of closure - --> $DIR/closure-substs.rs:41:9 - | -LL | |x: &i32, b: fn(&'static i32)| { - | - - `b` is declared here, outside of the closure body - | | - | `x` is a reference that is only valid in the closure body -LL | b(x); //~ ERROR +LL | b(x); //~ ERROR borrowed data escapes outside of closure | ^^^^ `x` escapes the closure body here -error: unsatisfied lifetime constraints - --> $DIR/closure-substs.rs:41:9 - | -LL | |x: &i32, b: fn(&'static i32)| { - | ------------------------------ - | | | - | | let's call the lifetime of this reference `'1` - | lifetime `'2` represents this closure's body -LL | b(x); //~ ERROR - | ^^^^ argument requires that `'1` must outlive `'2` - | - = note: closure implements `Fn`, so references to captured variables can't escape the closure - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/regions-static-bound.ll.stderr b/src/test/ui/regions/regions-static-bound.ll.stderr index 16add00eb41e1..cf291279210c9 100644 --- a/src/test/ui/regions/regions-static-bound.ll.stderr +++ b/src/test/ui/regions/regions-static-bound.ll.stderr @@ -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 ()` diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr index dc3a32cec6ac7..462fbe8ee19bd 100644 --- a/src/test/ui/regions/regions-static-bound.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.nll.stderr @@ -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`. diff --git a/src/test/ui/regions/regions-static-bound.rs b/src/test/ui/regions/regions-static-bound.rs index 34baf5ffff0a7..c5dc6000e839c 100644 --- a/src/test/ui/regions/regions-static-bound.rs +++ b/src/test/ui/regions/regions-static-bound.rs @@ -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() {} From 1371cd27d04a9a850c9141b5657367a4706ce60d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Oct 2018 10:30:41 -0400 Subject: [PATCH 09/10] check the self type is well-formed This fixes `issue-28848.rs` -- it also handles another case that the AST region checker gets wrong (`wf-self-type.rs`). I don't actually think that this is the *right way* to be enforcing this constraint -- I think we should probably do it more generally, perhaps by editing `predicates_of` for the impl itself. The chalk-style implied bounds setup ought to fix this. --- .../borrow_check/nll/type_check/mod.rs | 2 ++ src/test/ui/issues/issue-28848.rs | 2 -- src/test/ui/issues/issue-28848.stderr | 10 ++++---- .../ui/nll/user-annotations/wf-self-type.rs | 25 +++++++++++++++++++ .../nll/user-annotations/wf-self-type.stderr | 12 +++++++++ 5 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/wf-self-type.rs create mode 100644 src/test/ui/nll/user-annotations/wf-self-type.stderr diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 6d152fc87bd33..182e31a77b1b4 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1033,6 +1033,8 @@ 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`. diff --git a/src/test/ui/issues/issue-28848.rs b/src/test/ui/issues/issue-28848.rs index c13fd5fa71669..1a06d59f0b191 100644 --- a/src/test/ui/issues/issue-28848.rs +++ b/src/test/ui/issues/issue-28848.rs @@ -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> { diff --git a/src/test/ui/issues/issue-28848.stderr b/src/test/ui/issues/issue-28848.stderr index dadcff226f53b..738a1c0c6f616 100644 --- a/src/test/ui/issues/issue-28848.stderr +++ b/src/test/ui/issues/issue-28848.stderr @@ -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 () { | ^^ diff --git a/src/test/ui/nll/user-annotations/wf-self-type.rs b/src/test/ui/nll/user-annotations/wf-self-type.rs new file mode 100644 index 0000000000000..c3cb3068bcecf --- /dev/null +++ b/src/test/ui/nll/user-annotations/wf-self-type.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/nll/user-annotations/wf-self-type.stderr b/src/test/ui/nll/user-annotations/wf-self-type.stderr new file mode 100644 index 0000000000000..78d86fbf17ec0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/wf-self-type.stderr @@ -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 + From 4394c83cb7685e1bbaf733a6610df58d34c892ab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Oct 2018 10:57:06 -0400 Subject: [PATCH 10/10] type_check/mod.rs: rustfmt --- .../borrow_check/nll/type_check/mod.rs | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 182e31a77b1b4..6db107344747e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1034,7 +1034,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.eq_types(self_ty, impl_self_ty, locations, category)?; - self.prove_predicate(ty::Predicate::WellFormed(impl_self_ty), locations, category); + self.prove_predicate( + ty::Predicate::WellFormed(impl_self_ty), + locations, + category, + ); } // Prove the predicates coming along with `def_id`. @@ -1072,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( - &self, - value: T - ) -> T - where T: TypeFoldable<'tcx> + fn fold_to_region_vid(&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| { @@ -1212,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 { @@ -1225,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 } @@ -1512,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 { @@ -1526,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 } @@ -1584,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,