From 1cb555a1dc809a8d310354678ef9c43f01e41ad4 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 20 Feb 2020 11:05:24 -0800 Subject: Backport only: avoid ICE on bad placeholder type #69148 has a proper fix, but it is too big to backport. This change avoids the ICE by actually emitting an appropriate error. The output will be duplicated in some cases, but that's better than the avoidable ICE. --- src/librustc_typeck/collect.rs | 2 +- src/test/ui/did_you_mean/bad-assoc-ty.rs | 1 + src/test/ui/did_you_mean/bad-assoc-ty.stderr | 26 +- src/test/ui/self/self-infer.rs | 2 + src/test/ui/self/self-infer.stderr | 16 +- src/test/ui/typeck/typeck_type_placeholder_item.rs | 34 +++ .../ui/typeck/typeck_type_placeholder_item.stderr | 316 +++++++++++++++++---- 7 files changed, 329 insertions(+), 68 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 80d914d8d0a..79dc1817498 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -319,7 +319,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - self.tcx().sess.delay_span_bug(span, "bad placeholder type"); + placeholder_type_error(self.tcx(), span, &[], vec![span], false); self.tcx().types.err } diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index fccfb7911ce..f02931eeb6f 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -17,6 +17,7 @@ type D = (u8, u8)::AssocTy; type E = _::AssocTy; //~^ ERROR missing angle brackets in associated item path //~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures type F = &'static (u8)::AssocTy; //~^ ERROR missing angle brackets in associated item path diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 64e49934d87..d5b2abf2f8b 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -29,25 +29,25 @@ LL | type E = _::AssocTy; | ^^^^^^^^^^ help: try: `<_>::AssocTy` error: missing angle brackets in associated item path - --> $DIR/bad-assoc-ty.rs:21:19 + --> $DIR/bad-assoc-ty.rs:22:19 | LL | type F = &'static (u8)::AssocTy; | ^^^^^^^^^^^^^ help: try: `<(u8)>::AssocTy` error: missing angle brackets in associated item path - --> $DIR/bad-assoc-ty.rs:27:10 + --> $DIR/bad-assoc-ty.rs:28:10 | LL | type G = dyn 'static + (Send)::AssocTy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `::AssocTy` error: missing angle brackets in associated item path - --> $DIR/bad-assoc-ty.rs:44:10 + --> $DIR/bad-assoc-ty.rs:45:10 | LL | type I = ty!()::AssocTy; | ^^^^^^^^^^^^^^ help: try: `::AssocTy` error: missing angle brackets in associated item path - --> $DIR/bad-assoc-ty.rs:37:19 + --> $DIR/bad-assoc-ty.rs:38:19 | LL | ($ty: ty) => ($ty::AssocTy); | ^^^^^^^^^^^^ help: try: `<$ty>::AssocTy` @@ -87,26 +87,32 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa LL | type E = _::AssocTy; | ^ not allowed in type signatures +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:17:10 + | +LL | type E = _::AssocTy; + | ^ not allowed in type signatures + error[E0223]: ambiguous associated type - --> $DIR/bad-assoc-ty.rs:21:19 + --> $DIR/bad-assoc-ty.rs:22:19 | LL | type F = &'static (u8)::AssocTy; | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` error[E0223]: ambiguous associated type - --> $DIR/bad-assoc-ty.rs:27:10 + --> $DIR/bad-assoc-ty.rs:28:10 | LL | type G = dyn 'static + (Send)::AssocTy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy` error[E0223]: ambiguous associated type - --> $DIR/bad-assoc-ty.rs:33:10 + --> $DIR/bad-assoc-ty.rs:34:10 | LL | type H = Fn(u8) -> (u8)::Output; | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output` error[E0223]: ambiguous associated type - --> $DIR/bad-assoc-ty.rs:37:19 + --> $DIR/bad-assoc-ty.rs:38:19 | LL | ($ty: ty) => ($ty::AssocTy); | ^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` @@ -117,12 +123,12 @@ LL | type J = ty!(u8); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0223]: ambiguous associated type - --> $DIR/bad-assoc-ty.rs:44:10 + --> $DIR/bad-assoc-ty.rs:45:10 | LL | type I = ty!()::AssocTy; | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/self/self-infer.rs b/src/test/ui/self/self-infer.rs index 0956f2a5691..77c80521236 100644 --- a/src/test/ui/self/self-infer.rs +++ b/src/test/ui/self/self-infer.rs @@ -2,7 +2,9 @@ struct S; impl S { fn f(self: _) {} //~ERROR the type placeholder `_` is not allowed within types on item sig + //~^ ERROR the type placeholder `_` is not allowed within types on item sig fn g(self: &_) {} //~ERROR the type placeholder `_` is not allowed within types on item sig + //~^ ERROR the type placeholder `_` is not allowed within types on item sig } fn main() {} diff --git a/src/test/ui/self/self-infer.stderr b/src/test/ui/self/self-infer.stderr index 1475b212b56..d6bf8b44d60 100644 --- a/src/test/ui/self/self-infer.stderr +++ b/src/test/ui/self/self-infer.stderr @@ -1,3 +1,9 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/self-infer.rs:4:16 + | +LL | fn f(self: _) {} + | ^ not allowed in type signatures + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/self-infer.rs:4:16 | @@ -10,7 +16,13 @@ LL | fn f(self: T) {} | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/self-infer.rs:5:17 + --> $DIR/self-infer.rs:6:17 + | +LL | fn g(self: &_) {} + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/self-infer.rs:6:17 | LL | fn g(self: &_) {} | ^ not allowed in type signatures @@ -20,6 +32,6 @@ help: use type parameters instead LL | fn g(self: &T) {} | ^^^ ^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 86c7c52b271..eb6cc832fb4 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -19,19 +19,24 @@ static TEST5: (_, _) = (1, 2); fn test6(_: _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn test6_b(_: _, _: T) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn test6_c(_: _, _: (T, K, L, A, B)) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn test7(x: _) { let _x: usize = x; } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures //~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures struct Test9; @@ -41,6 +46,7 @@ impl Test9 { fn test10(&self, _x : _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } fn test11(x: &usize) -> &_ { @@ -59,12 +65,16 @@ impl Clone for Test9 { fn clone_from(&mut self, other: _) { *self = Test9; } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } struct Test10 { a: _, //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures b: (_, _), + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } pub fn main() { @@ -92,13 +102,16 @@ pub fn main() { fn fn_test6(_: _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn fn_test7(x: _) { let _x: usize = x; } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn fn_test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures //~| ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures struct FnTest9; @@ -108,6 +121,7 @@ pub fn main() { fn fn_test10(&self, _x : _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } impl Clone for FnTest9 { @@ -116,12 +130,16 @@ pub fn main() { fn clone_from(&mut self, other: _) { *self = FnTest9; } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } struct FnTest10 { a: _, //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures b: (_, _), + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } fn fn_test11(_: _) -> (_, _) { panic!() } @@ -138,28 +156,40 @@ pub fn main() { trait T { fn method_test1(&self, x: _); //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn method_test2(&self, x: _) -> _; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn method_test3(&self) -> _; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn assoc_fn_test1(x: _); //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn assoc_fn_test2(x: _) -> _; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures fn assoc_fn_test3() -> _; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } struct BadStruct<_>(_); //~^ ERROR expected identifier, found reserved identifier `_` //~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures trait BadTrait<_> {} //~^ ERROR expected identifier, found reserved identifier `_` impl BadTrait<_> for BadStruct<_> {} //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn impl_trait() -> impl BadTrait<_> { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures unimplemented!() } @@ -168,18 +198,22 @@ struct BadStruct1<_, _>(_); //~| ERROR expected identifier, found reserved identifier `_` //~| ERROR the name `_` is already used //~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures struct BadStruct2<_, T>(_, T); //~^ ERROR expected identifier, found reserved identifier `_` //~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures type X = Box<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures struct Struct; trait Trait {} impl Trait for Struct {} type Y = impl Trait<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn foo() -> Y { Struct } diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 95e8f94c6f3..a8fdd66ee37 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,35 +1,35 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:153:18 + --> $DIR/typeck_type_placeholder_item.rs:179:18 | LL | struct BadStruct<_>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:156:16 + --> $DIR/typeck_type_placeholder_item.rs:183:16 | LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:166:19 + --> $DIR/typeck_type_placeholder_item.rs:196:19 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:166:22 + --> $DIR/typeck_type_placeholder_item.rs:196:22 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:171:19 + --> $DIR/typeck_type_placeholder_item.rs:202:19 | LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters - --> $DIR/typeck_type_placeholder_item.rs:166:22 + --> $DIR/typeck_type_placeholder_item.rs:196:22 | LL | struct BadStruct1<_, _>(_); | - ^ already used @@ -79,6 +79,12 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa LL | static TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:20:13 + | +LL | fn test6(_: _) { } + | ^ not allowed in type signatures + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:20:13 | @@ -91,7 +97,13 @@ LL | fn test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:23:18 + --> $DIR/typeck_type_placeholder_item.rs:24:18 + | +LL | fn test6_b(_: _, _: T) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:24:18 | LL | fn test6_b(_: _, _: T) { } | ^ not allowed in type signatures @@ -102,7 +114,13 @@ LL | fn test6_b(_: K, _: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:26:30 + --> $DIR/typeck_type_placeholder_item.rs:28:30 + | +LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:28:30 | LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } | ^ not allowed in type signatures @@ -113,7 +131,13 @@ LL | fn test6_c(_: C, _: (T, K, L, A, B)) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:29:13 + --> $DIR/typeck_type_placeholder_item.rs:32:13 + | +LL | fn test7(x: _) { let _x: usize = x; } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:32:13 | LL | fn test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -124,13 +148,19 @@ LL | fn test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:32:22 + --> $DIR/typeck_type_placeholder_item.rs:36:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:32:22 + --> $DIR/typeck_type_placeholder_item.rs:36:22 + | +LL | fn test8(_f: fn() -> _) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:36:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -141,7 +171,61 @@ LL | fn test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:46:26 + --> $DIR/typeck_type_placeholder_item.rs:72:8 + | +LL | a: _, + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:75:9 + | +LL | b: (_, _), + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:75:12 + | +LL | b: (_, _), + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:137:12 + | +LL | a: _, + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:140:13 + | +LL | b: (_, _), + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:140:16 + | +LL | b: (_, _), + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:179:21 + | +LL | struct BadStruct<_>(_); + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:196:25 + | +LL | struct BadStruct1<_, _>(_); + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:202:25 + | +LL | struct BadStruct2<_, T>(_, T); + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:52:26 | LL | fn test11(x: &usize) -> &_ { | -^ @@ -150,7 +234,7 @@ LL | fn test11(x: &usize) -> &_ { | help: replace with the correct return type: `&&usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:51:52 + --> $DIR/typeck_type_placeholder_item.rs:57:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { | --------------^ @@ -159,11 +243,11 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ { | help: replace with the correct return type: `*const *const usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:65:8 + --> $DIR/typeck_type_placeholder_item.rs:72:8 | LL | a: _, | ^ not allowed in type signatures -LL | +... LL | b: (_, _), | ^ ^ not allowed in type signatures | | @@ -174,17 +258,18 @@ help: use type parameters instead LL | struct Test10 { LL | a: T, LL | +LL | LL | b: (T, T), | error: missing type for `static` item - --> $DIR/typeck_type_placeholder_item.rs:71:12 + --> $DIR/typeck_type_placeholder_item.rs:81:12 | LL | static A = 42; | ^ help: provide a type for the item: `A: i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:73:15 + --> $DIR/typeck_type_placeholder_item.rs:83:15 | LL | static B: _ = 42; | ^ @@ -193,13 +278,13 @@ LL | static B: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:75:15 + --> $DIR/typeck_type_placeholder_item.rs:85:15 | LL | static C: Option<_> = Some(42); | ^^^^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:78:21 + --> $DIR/typeck_type_placeholder_item.rs:88:21 | LL | fn fn_test() -> _ { 5 } | ^ @@ -208,7 +293,7 @@ LL | fn fn_test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:23 + --> $DIR/typeck_type_placeholder_item.rs:91:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } | -^--^- @@ -218,7 +303,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:84:22 + --> $DIR/typeck_type_placeholder_item.rs:94:22 | LL | static FN_TEST3: _ = "test"; | ^ @@ -227,7 +312,7 @@ LL | static FN_TEST3: _ = "test"; | help: replace `_` with the correct type: `&'static str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:87:22 + --> $DIR/typeck_type_placeholder_item.rs:97:22 | LL | static FN_TEST4: _ = 145; | ^ @@ -236,13 +321,19 @@ LL | static FN_TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:90:22 + --> $DIR/typeck_type_placeholder_item.rs:100:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:93:20 + --> $DIR/typeck_type_placeholder_item.rs:103:20 + | +LL | fn fn_test6(_: _) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:103:20 | LL | fn fn_test6(_: _) { } | ^ not allowed in type signatures @@ -253,7 +344,13 @@ LL | fn fn_test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:96:20 + --> $DIR/typeck_type_placeholder_item.rs:107:20 + | +LL | fn fn_test7(x: _) { let _x: usize = x; } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:107:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -264,13 +361,19 @@ LL | fn fn_test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:111:29 + | +LL | fn fn_test8(_f: fn() -> _) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:111:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:111:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -281,11 +384,11 @@ LL | fn fn_test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:122:12 + --> $DIR/typeck_type_placeholder_item.rs:137:12 | LL | a: _, | ^ not allowed in type signatures -LL | +... LL | b: (_, _), | ^ ^ not allowed in type signatures | | @@ -296,17 +399,18 @@ help: use type parameters instead LL | struct FnTest10 { LL | a: T, LL | +LL | LL | b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:127:18 + --> $DIR/typeck_type_placeholder_item.rs:145:18 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ cannot infer type error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:127:28 + --> $DIR/typeck_type_placeholder_item.rs:145:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ ^ not allowed in type signatures @@ -314,7 +418,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:131:30 + --> $DIR/typeck_type_placeholder_item.rs:149:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | -^--^- @@ -324,7 +428,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:134:33 + --> $DIR/typeck_type_placeholder_item.rs:152:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | ------^- @@ -333,7 +437,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:153:21 + --> $DIR/typeck_type_placeholder_item.rs:179:21 | LL | struct BadStruct<_>(_); | ^ not allowed in type signatures @@ -344,7 +448,19 @@ LL | struct BadStruct(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:158:15 + --> $DIR/typeck_type_placeholder_item.rs:185:32 + | +LL | impl BadTrait<_> for BadStruct<_> {} + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:185:15 + | +LL | impl BadTrait<_> for BadStruct<_> {} + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:185:15 | LL | impl BadTrait<_> for BadStruct<_> {} | ^ ^ not allowed in type signatures @@ -357,13 +473,13 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:161:34 + --> $DIR/typeck_type_placeholder_item.rs:190:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:166:25 + --> $DIR/typeck_type_placeholder_item.rs:196:25 | LL | struct BadStruct1<_, _>(_); | ^ not allowed in type signatures @@ -374,7 +490,7 @@ LL | struct BadStruct1(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:171:25 + --> $DIR/typeck_type_placeholder_item.rs:202:25 | LL | struct BadStruct2<_, T>(_, T); | ^ not allowed in type signatures @@ -385,13 +501,25 @@ LL | struct BadStruct2(K, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:175:14 + --> $DIR/typeck_type_placeholder_item.rs:207:14 | LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:42:27 + --> $DIR/typeck_type_placeholder_item.rs:207:14 + | +LL | type X = Box<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:47:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:47:27 | LL | fn test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -402,7 +530,13 @@ LL | fn test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:139:31 + --> $DIR/typeck_type_placeholder_item.rs:157:31 + | +LL | fn method_test1(&self, x: _); + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:157:31 | LL | fn method_test1(&self, x: _); | ^ not allowed in type signatures @@ -413,7 +547,19 @@ LL | fn method_test1(&self, x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:141:31 + --> $DIR/typeck_type_placeholder_item.rs:160:37 + | +LL | fn method_test2(&self, x: _) -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:160:31 + | +LL | fn method_test2(&self, x: _) -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:160:31 | LL | fn method_test2(&self, x: _) -> _; | ^ ^ not allowed in type signatures @@ -426,7 +572,13 @@ LL | fn method_test2(&self, x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:143:31 + --> $DIR/typeck_type_placeholder_item.rs:164:31 + | +LL | fn method_test3(&self) -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:164:31 | LL | fn method_test3(&self) -> _; | ^ not allowed in type signatures @@ -437,7 +589,13 @@ LL | fn method_test3(&self) -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:145:26 + --> $DIR/typeck_type_placeholder_item.rs:167:26 + | +LL | fn assoc_fn_test1(x: _); + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:167:26 | LL | fn assoc_fn_test1(x: _); | ^ not allowed in type signatures @@ -448,7 +606,19 @@ LL | fn assoc_fn_test1(x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:147:26 + --> $DIR/typeck_type_placeholder_item.rs:170:32 + | +LL | fn assoc_fn_test2(x: _) -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:170:26 + | +LL | fn assoc_fn_test2(x: _) -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:170:26 | LL | fn assoc_fn_test2(x: _) -> _; | ^ ^ not allowed in type signatures @@ -461,7 +631,13 @@ LL | fn assoc_fn_test2(x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:149:28 + --> $DIR/typeck_type_placeholder_item.rs:174:28 + | +LL | fn assoc_fn_test3() -> _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:174:28 | LL | fn assoc_fn_test3() -> _; | ^ not allowed in type signatures @@ -472,7 +648,13 @@ LL | fn assoc_fn_test3() -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:60:37 + --> $DIR/typeck_type_placeholder_item.rs:66:37 + | +LL | fn clone_from(&mut self, other: _) { *self = Test9; } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:66:37 | LL | fn clone_from(&mut self, other: _) { *self = Test9; } | ^ not allowed in type signatures @@ -483,7 +665,13 @@ LL | fn clone_from(&mut self, other: T) { *self = Test9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:109:34 + --> $DIR/typeck_type_placeholder_item.rs:122:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:122:34 | LL | fn fn_test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -494,7 +682,13 @@ LL | fn fn_test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:117:41 + --> $DIR/typeck_type_placeholder_item.rs:131:41 + | +LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:131:41 | LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } | ^ not allowed in type signatures @@ -505,13 +699,25 @@ LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:181:21 + --> $DIR/typeck_type_placeholder_item.rs:190:34 + | +LL | fn impl_trait() -> impl BadTrait<_> { + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:214:21 + | +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:214:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:39:24 + --> $DIR/typeck_type_placeholder_item.rs:44:24 | LL | fn test9(&self) -> _ { () } | ^ @@ -520,7 +726,7 @@ LL | fn test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:57:24 + --> $DIR/typeck_type_placeholder_item.rs:63:24 | LL | fn clone(&self) -> _ { Test9 } | ^ @@ -529,7 +735,7 @@ LL | fn clone(&self) -> _ { Test9 } | help: replace with the correct return type: `Test9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:106:31 + --> $DIR/typeck_type_placeholder_item.rs:119:31 | LL | fn fn_test9(&self) -> _ { () } | ^ @@ -538,7 +744,7 @@ LL | fn fn_test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:114:28 + --> $DIR/typeck_type_placeholder_item.rs:128:28 | LL | fn clone(&self) -> _ { FnTest9 } | ^ @@ -546,7 +752,7 @@ LL | fn clone(&self) -> _ { FnTest9 } | not allowed in type signatures | help: replace with the correct return type: `main::FnTest9` -error: aborting due to 58 previous errors +error: aborting due to 92 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. -- cgit 1.4.1-3-g733a5 From f7d55be7e58e15cbc433748715b1dc67adfc5d06 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 24 Feb 2020 21:44:55 +0300 Subject: resolve: `lifetimes.rs` -> `late/lifetime.rs` --- src/librustc_resolve/diagnostics.rs | 243 +-- src/librustc_resolve/late.rs | 1 + src/librustc_resolve/late/diagnostics.rs | 243 ++- src/librustc_resolve/late/lifetimes.rs | 2911 ++++++++++++++++++++++++++++++ src/librustc_resolve/lib.rs | 3 +- src/librustc_resolve/lifetimes.rs | 2911 ------------------------------ 6 files changed, 3156 insertions(+), 3156 deletions(-) create mode 100644 src/librustc_resolve/late/lifetimes.rs delete mode 100644 src/librustc_resolve/lifetimes.rs diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 7c48ccfaddd..bf9eeb0b6c5 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -6,9 +6,8 @@ use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_feature::BUILTIN_ATTRIBUTES; -use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -20,7 +19,6 @@ use syntax::ast::{self, Ident, Path}; use syntax::util::lev_distance::find_best_match_for_name; use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}; use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot}; @@ -49,40 +47,6 @@ crate struct ImportSuggestion { pub path: Path, } -crate enum MissingLifetimeSpot<'tcx> { - Generics(&'tcx hir::Generics<'tcx>), - HigherRanked { span: Span, span_type: ForLifetimeSpanType }, -} - -crate enum ForLifetimeSpanType { - BoundEmpty, - BoundTail, - TypeEmpty, - TypeTail, -} - -impl ForLifetimeSpanType { - crate fn descr(&self) -> &'static str { - match self { - Self::BoundEmpty | Self::BoundTail => "bound", - Self::TypeEmpty | Self::TypeTail => "type", - } - } - - crate fn suggestion(&self, sugg: &str) -> String { - match self { - Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), - Self::BoundTail | Self::TypeTail => format!(", {}", sugg), - } - } -} - -impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { - fn into(self) -> MissingLifetimeSpot<'tcx> { - MissingLifetimeSpot::Generics(self) - } -} - /// Adjust the impl span so that just the `impl` keyword is taken by removing /// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). @@ -1491,208 +1455,3 @@ crate fn show_candidates( err.note(&msg); } } - -impl<'tcx> LifetimeContext<'_, 'tcx> { - crate fn report_missing_lifetime_specifiers( - &self, - span: Span, - count: usize, - ) -> DiagnosticBuilder<'tcx> { - struct_span_err!( - self.tcx.sess, - span, - E0106, - "missing lifetime specifier{}", - pluralize!(count) - ) - } - - crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0261, - "use of undeclared lifetime name `{}`", - lifetime_ref - ); - err.span_label(lifetime_ref.span, "undeclared lifetime"); - for missing in &self.missing_named_lifetime_spots { - match missing { - MissingLifetimeSpot::Generics(generics) => { - let (span, sugg) = if let Some(param) = generics - .params - .iter() - .filter(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }) - .next() - { - (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) - } else { - (generics.span, format!("<{}>", lifetime_ref)) - }; - err.span_suggestion( - span, - &format!("consider introducing lifetime `{}` here", lifetime_ref), - sugg, - Applicability::MaybeIncorrect, - ); - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - err.span_suggestion( - *span, - &format!( - "consider making the {} lifetime-generic with a new `{}` lifetime", - span_type.descr(), - lifetime_ref - ), - span_type.suggestion(&lifetime_ref.to_string()), - Applicability::MaybeIncorrect, - ); - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - } - } - } - err.emit(); - } - - crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { - if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { - if [ - self.tcx.lang_items().fn_once_trait(), - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - ] - .contains(&Some(did)) - { - let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), - [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), - }; - self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HigherRanked { span, span_type }); - return true; - } - }; - false - } - - crate fn add_missing_lifetime_specifiers_label( - &self, - err: &mut DiagnosticBuilder<'_>, - span: Span, - count: usize, - lifetime_names: &FxHashSet, - params: &[ElisionFailureInfo], - ) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else { - let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_suggestion( - span, - "consider using the named lifetime", - sugg, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = - |err: &mut DiagnosticBuilder<'_>, sugg: &str| { - err.span_label(span, "expected named lifetime parameter"); - - for missing in self.missing_named_lifetime_spots.iter().rev() { - let mut introduce_suggestion = vec![]; - let msg; - let should_break; - introduce_suggestion.push(match missing { - MissingLifetimeSpot::Generics(generics) => { - msg = "consider introducing a named lifetime parameter".to_string(); - should_break = true; - if let Some(param) = generics.params.iter().filter(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }).next() { - (param.span.shrink_to_lo(), "'a, ".to_string()) - } else { - (generics.span, "<'a>".to_string()) - } - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - msg = format!( - "consider making the {} lifetime-generic with a new `'a` lifetime", - span_type.descr(), - ); - should_break = false; - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - (*span, span_type.suggestion("'a")) - } - }); - for param in params { - if let Ok(snippet) = - self.tcx.sess.source_map().span_to_snippet(param.span) - { - if snippet.starts_with("&") && !snippet.starts_with("&'") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[4..]))); - } - } - } - introduce_suggestion.push((span, sugg.to_string())); - err.multipart_suggestion( - &msg, - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - if should_break { - break; - } - } - }; - - match ( - lifetime_names.len(), - lifetime_names.iter().next(), - snippet.as_ref().map(|s| s.as_str()), - ) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); - } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); - } - (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { - suggest_existing(err, format!("{}<{}>", snippet, name)); - } - (0, _, Some("&")) => { - suggest_new(err, "&'a "); - } - (0, _, Some("'_")) => { - suggest_new(err, "'a"); - } - (0, _, Some(snippet)) if !snippet.ends_with(">") => { - suggest_new(err, &format!("{}<'a>", snippet)); - } - _ => { - err.span_label(span, "expected lifetime parameter"); - } - } - } - } -} diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 5b5180a7e1a..c924fef4dc9 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -32,6 +32,7 @@ use std::collections::BTreeSet; use std::mem::replace; mod diagnostics; +crate mod lifetimes; type Res = def::Res; diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 6a6fba8270b..2beda186da0 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1,4 +1,5 @@ use crate::diagnostics::{ImportSuggestion, TypoSuggestion}; +use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; use crate::late::{LateResolutionVisitor, RibKind}; use crate::path_names_to_string; use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; @@ -6,7 +7,8 @@ use crate::{PathResult, PathSource, Segment}; use rustc::session::config::nightly_options; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -28,6 +30,40 @@ enum AssocSuggestion { AssocItem, } +crate enum MissingLifetimeSpot<'tcx> { + Generics(&'tcx hir::Generics<'tcx>), + HigherRanked { span: Span, span_type: ForLifetimeSpanType }, +} + +crate enum ForLifetimeSpanType { + BoundEmpty, + BoundTail, + TypeEmpty, + TypeTail, +} + +impl ForLifetimeSpanType { + crate fn descr(&self) -> &'static str { + match self { + Self::BoundEmpty | Self::BoundTail => "bound", + Self::TypeEmpty | Self::TypeTail => "type", + } + } + + crate fn suggestion(&self, sugg: &str) -> String { + match self { + Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), + Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + } + } +} + +impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { + fn into(self) -> MissingLifetimeSpot<'tcx> { + MissingLifetimeSpot::Generics(self) + } +} + fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper } @@ -904,3 +940,208 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { None } } + +impl<'tcx> LifetimeContext<'_, 'tcx> { + crate fn report_missing_lifetime_specifiers( + &self, + span: Span, + count: usize, + ) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + self.tcx.sess, + span, + E0106, + "missing lifetime specifier{}", + pluralize!(count) + ) + } + + crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0261, + "use of undeclared lifetime name `{}`", + lifetime_ref + ); + err.span_label(lifetime_ref.span, "undeclared lifetime"); + for missing in &self.missing_named_lifetime_spots { + match missing { + MissingLifetimeSpot::Generics(generics) => { + let (span, sugg) = if let Some(param) = generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .next() + { + (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref)) + } else { + (generics.span, format!("<{}>", lifetime_ref)) + }; + err.span_suggestion( + span, + &format!("consider introducing lifetime `{}` here", lifetime_ref), + sugg, + Applicability::MaybeIncorrect, + ); + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + err.span_suggestion( + *span, + &format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lifetime_ref + ), + span_type.suggestion(&lifetime_ref.to_string()), + Applicability::MaybeIncorrect, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + } + } + } + err.emit(); + } + + crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool { + if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res { + if [ + self.tcx.lang_items().fn_once_trait(), + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + ] + .contains(&Some(did)) + { + let (span, span_type) = match &trait_ref.bound_generic_params { + [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), + [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + return true; + } + }; + false + } + + crate fn add_missing_lifetime_specifiers_label( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, + lifetime_names: &FxHashSet, + params: &[ElisionFailureInfo], + ) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); + } else { + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion( + span, + "consider using the named lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = + |err: &mut DiagnosticBuilder<'_>, sugg: &str| { + err.span_label(span, "expected named lifetime parameter"); + + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + if let Some(param) = generics.params.iter().filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }).next() { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) + } + } + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + (*span, span_type.suggestion("'a")) + } + }); + for param in params { + if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(param.span) + { + if snippet.starts_with("&") && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } + } + } + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion( + &msg, + introduce_suggestion, + Applicability::MaybeIncorrect, + ); + if should_break { + break; + } + } + }; + + match ( + lifetime_names.len(), + lifetime_names.iter().next(), + snippet.as_ref().map(|s| s.as_str()), + ) { + (1, Some(name), Some("&")) => { + suggest_existing(err, format!("&{} ", name)); + } + (1, Some(name), Some("'_")) => { + suggest_existing(err, name.to_string()); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with(">") => { + suggest_existing(err, format!("{}<{}>", snippet, name)); + } + (0, _, Some("&")) => { + suggest_new(err, "&'a "); + } + (0, _, Some("'_")) => { + suggest_new(err, "'a"); + } + (0, _, Some(snippet)) if !snippet.ends_with(">") => { + suggest_new(err, &format!("{}<'a>", snippet)); + } + _ => { + err.span_label(span, "expected lifetime parameter"); + } + } + } + } +} diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs new file mode 100644 index 00000000000..478757f0db7 --- /dev/null +++ b/src/librustc_resolve/late/lifetimes.rs @@ -0,0 +1,2911 @@ +//! Name resolution for lifetimes. +//! +//! Name resolution for lifetimes follows *much* simpler rules than the +//! full resolve. For example, lifetime names are never exported or +//! used between functions, and they operate in a purely top-down +//! way. Therefore, we break lifetime name resolution into a separate pass. + +use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; +use rustc::hir::map::Map; +use rustc::lint; +use rustc::middle::resolve_lifetime::*; +use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; +use rustc::{bug, span_bug}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; +use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind}; +use rustc_span::symbol::{kw, sym}; +use rustc_span::Span; +use std::borrow::Cow; +use std::cell::Cell; +use std::mem::{replace, take}; +use syntax::ast; +use syntax::attr; +use syntax::walk_list; + +use log::debug; + +// This counts the no of times a lifetime is used +#[derive(Clone, Copy, Debug)] +pub enum LifetimeUseSet<'tcx> { + One(&'tcx hir::Lifetime), + Many, +} + +trait RegionExt { + fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); + + fn late_anon(index: &Cell) -> Region; + + fn id(&self) -> Option; + + fn shifted(self, amount: u32) -> Region; + + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; + + fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option + where + L: Iterator; +} + +impl RegionExt for Region { + fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { + let i = *index; + *index += 1; + let def_id = hir_map.local_def_id(param.hir_id); + let origin = LifetimeDefOrigin::from_param(param); + debug!("Region::early: index={} def_id={:?}", i, def_id); + (param.name.modern(), Region::EarlyBound(i, def_id, origin)) + } + + fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { + let depth = ty::INNERMOST; + let def_id = hir_map.local_def_id(param.hir_id); + let origin = LifetimeDefOrigin::from_param(param); + debug!( + "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", + param, depth, def_id, origin, + ); + (param.name.modern(), Region::LateBound(depth, def_id, origin)) + } + + fn late_anon(index: &Cell) -> Region { + let i = index.get(); + index.set(i + 1); + let depth = ty::INNERMOST; + Region::LateBoundAnon(depth, i) + } + + fn id(&self) -> Option { + match *self { + Region::Static | Region::LateBoundAnon(..) => None, + + Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => { + Some(id) + } + } + } + + fn shifted(self, amount: u32) -> Region { + match self { + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_in(amount), id, origin) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_in(amount), index) + } + _ => self, + } + } + + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { + match self { + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) + } + _ => self, + } + } + + fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option + where + L: Iterator, + { + if let Region::EarlyBound(index, _, _) = self { + params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) + } else { + Some(self) + } + } +} + +/// Maps the id of each lifetime reference to the lifetime decl +/// that it corresponds to. +/// +/// FIXME. This struct gets converted to a `ResolveLifetimes` for +/// actual use. It has the same data, but indexed by `DefIndex`. This +/// is silly. +#[derive(Default)] +struct NamedRegionMap { + // maps from every use of a named (not anonymous) lifetime to a + // `Region` describing how that region is bound + defs: HirIdMap, + + // the set of lifetime def ids that are late-bound; a region can + // be late-bound if (a) it does NOT appear in a where-clause and + // (b) it DOES appear in the arguments. + late_bound: HirIdSet, + + // For each type and trait definition, maps type parameters + // to the trait object lifetime defaults computed from them. + object_lifetime_defaults: HirIdMap>, +} + +crate struct LifetimeContext<'a, 'tcx> { + crate tcx: TyCtxt<'tcx>, + map: &'a mut NamedRegionMap, + scope: ScopeRef<'a>, + + /// This is slightly complicated. Our representation for poly-trait-refs contains a single + /// binder and thus we only allow a single level of quantification. However, + /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` + /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the De Bruijn indices + /// correct when representing these constraints, we should only introduce one + /// scope. However, we want to support both locations for the quantifier and + /// during lifetime resolution we want precise information (so we can't + /// desugar in an earlier phase). + /// + /// So, if we encounter a quantifier at the outer scope, we set + /// `trait_ref_hack` to `true` (and introduce a scope), and then if we encounter + /// a quantifier at the inner scope, we error. If `trait_ref_hack` is `false`, + /// then we introduce the scope at the inner quantifier. + trait_ref_hack: bool, + + /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. + is_in_fn_syntax: bool, + + /// List of labels in the function/method currently under analysis. + labels_in_fn: Vec, + + /// Cache for cross-crate per-definition object lifetime defaults. + xcrate_object_lifetime_defaults: DefIdMap>, + + lifetime_uses: &'a mut DefIdMap>, + + /// When encountering an undefined named lifetime, we will suggest introducing it in these + /// places. + crate missing_named_lifetime_spots: Vec>, +} + +#[derive(Debug)] +enum Scope<'a> { + /// Declares lifetimes, and each can be early-bound or late-bound. + /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// it should be shifted by the number of `Binder`s in between the + /// declaration `Binder` and the location it's referenced from. + Binder { + lifetimes: FxHashMap, + + /// if we extend this scope with another scope, what is the next index + /// we should use for an early-bound region? + next_early_index: u32, + + /// Flag is set to true if, in this binder, `'_` would be + /// equivalent to a "single-use region". This is true on + /// impls, but not other kinds of items. + track_lifetime_uses: bool, + + /// Whether or not this binder would serve as the parent + /// binder for opaque types introduced within. For example: + /// + /// ```text + /// fn foo<'a>() -> impl for<'b> Trait> + /// ``` + /// + /// Here, the opaque types we create for the `impl Trait` + /// and `impl Trait2` references will both have the `foo` item + /// as their parent. When we get to `impl Trait2`, we find + /// that it is nested within the `for<>` binder -- this flag + /// allows us to skip that when looking for the parent binder + /// of the resulting opaque type. + opaque_type_parent: bool, + + s: ScopeRef<'a>, + }, + + /// Lifetimes introduced by a fn are scoped to the call-site for that fn, + /// if this is a fn body, otherwise the original definitions are used. + /// Unspecified lifetimes are inferred, unless an elision scope is nested, + /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. + Body { + id: hir::BodyId, + s: ScopeRef<'a>, + }, + + /// A scope which either determines unspecified lifetimes or errors + /// on them (e.g., due to ambiguity). For more details, see `Elide`. + Elision { + elide: Elide, + s: ScopeRef<'a>, + }, + + /// Use a specific lifetime (if `Some`) or leave it unset (to be + /// inferred in a function body or potentially error outside one), + /// for the default choice of lifetime in a trait object type. + ObjectLifetimeDefault { + lifetime: Option, + s: ScopeRef<'a>, + }, + + Root, +} + +#[derive(Clone, Debug)] +enum Elide { + /// Use a fresh anonymous late-bound lifetime each time, by + /// incrementing the counter to generate sequential indices. + FreshLateAnon(Cell), + /// Always use this one lifetime. + Exact(Region), + /// Less or more than one lifetime were found, error on unspecified. + Error(Vec), +} + +#[derive(Clone, Debug)] +crate struct ElisionFailureInfo { + /// Where we can find the argument pattern. + parent: Option, + /// The index of the argument in the original definition. + index: usize, + lifetime_count: usize, + have_bound_regions: bool, + crate span: Span, +} + +type ScopeRef<'a> = &'a Scope<'a>; + +const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { + resolve_lifetimes, + + named_region_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id) + }, + + is_late_bound_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id) + }, + + object_lifetime_defaults_map: |tcx, id| { + let id = LocalDefId::from_def_id(DefId::local(id)); // (*) + tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) + }, + + ..*providers + }; + + // (*) FIXME the query should be defined to take a LocalDefId +} + +/// Computes the `ResolveLifetimes` map that contains data for the +/// entire crate. You should not read the result of this query +/// directly, but rather use `named_region_map`, `is_late_bound_map`, +/// etc. +fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes { + assert_eq!(for_krate, LOCAL_CRATE); + + let named_region_map = krate(tcx); + + let mut rl = ResolveLifetimes::default(); + + for (hir_id, v) in named_region_map.defs { + let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + for hir_id in named_region_map.late_bound { + let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id); + } + for (hir_id, v) in named_region_map.object_lifetime_defaults { + let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default(); + map.insert(hir_id.local_id, v); + } + + tcx.arena.alloc(rl) +} + +fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { + let krate = tcx.hir().krate(); + let mut map = NamedRegionMap { + defs: Default::default(), + late_bound: Default::default(), + object_lifetime_defaults: compute_object_lifetime_defaults(tcx), + }; + { + let mut visitor = LifetimeContext { + tcx, + map: &mut map, + scope: ROOT_SCOPE, + trait_ref_hack: false, + is_in_fn_syntax: false, + labels_in_fn: vec![], + xcrate_object_lifetime_defaults: Default::default(), + lifetime_uses: &mut Default::default(), + missing_named_lifetime_spots: vec![], + }; + for (_, item) in &krate.items { + visitor.visit_item(item); + } + } + map +} + +/// In traits, there is an implicit `Self` type parameter which comes before the generics. +/// We have to account for this when computing the index of the other generic parameters. +/// This function returns whether there is such an implicit parameter defined on the given item. +fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { + match *node { + hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => true, + _ => false, + } +} + +impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::All(&self.tcx.hir()) + } + + // We want to nest trait/impl items in their parent, but nothing else. + fn visit_nested_item(&mut self, _: hir::ItemId) {} + + fn visit_nested_body(&mut self, body: hir::BodyId) { + // Each body has their own set of labels, save labels. + let saved = take(&mut self.labels_in_fn); + let body = self.tcx.hir().body(body); + extract_labels(self, body); + self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { + this.visit_body(body); + }); + replace(&mut self.labels_in_fn, saved); + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + match item.kind { + hir::ItemKind::Fn(ref sig, ref generics, _) => { + self.missing_named_lifetime_spots.push(generics.into()); + self.visit_early_late(None, &sig.decl, generics, |this| { + intravisit::walk_item(this, item); + }); + self.missing_named_lifetime_spots.pop(); + } + + hir::ItemKind::ExternCrate(_) + | hir::ItemKind::Use(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::GlobalAsm(..) => { + // These sorts of items have no lifetime parameters at all. + intravisit::walk_item(self, item); + } + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { + // No lifetime parameters, but implied 'static. + let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; + self.with(scope, |_, this| intravisit::walk_item(this, item)); + } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => { + // Currently opaque type declarations are just generated from `impl Trait` + // items. Doing anything on this node is irrelevant, as we currently don't need + // it. + } + hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: None, ref generics, .. + }) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::TraitAlias(ref generics, ..) + | hir::ItemKind::Impl { ref generics, .. } => { + self.missing_named_lifetime_spots.push(generics.into()); + + // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". + // This is not true for other kinds of items.x + let track_lifetime_uses = match item.kind { + hir::ItemKind::Impl { .. } => true, + _ => false, + }; + // These kinds of items have only early-bound lifetime parameters. + let mut index = if sub_items_have_self_param(&item.kind) { + 1 // Self comes before lifetimes + } else { + 0 + }; + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + opaque_type_parent: true, + track_lifetime_uses, + s: ROOT_SCOPE, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + intravisit::walk_item(this, item); + }); + self.missing_named_lifetime_spots.pop(); + } + } + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + match item.kind { + hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { + self.visit_early_late(None, decl, generics, |this| { + intravisit::walk_foreign_item(this, item); + }) + } + hir::ForeignItemKind::Static(..) => { + intravisit::walk_foreign_item(self, item); + } + hir::ForeignItemKind::Type => { + intravisit::walk_foreign_item(self, item); + } + } + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); + debug!("visit_ty: ty.kind={:?}", ty.kind); + match ty.kind { + hir::TyKind::BareFn(ref c) => { + let next_early_index = self.next_early_index(); + let was_in_fn_syntax = self.is_in_fn_syntax; + self.is_in_fn_syntax = true; + let lifetime_span: Option = c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param.span), + _ => None, + }) + .last(); + let (span, span_type) = if let Some(span) = lifetime_span { + (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) + } else { + (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + let scope = Scope::Binder { + lifetimes: c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(), + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |old_scope, this| { + // a bare fn has no bounds, so everything + // contained within is scoped within its binder. + this.check_lifetime_params(old_scope, &c.generic_params); + intravisit::walk_ty(this, ty); + }); + self.missing_named_lifetime_spots.pop(); + self.is_in_fn_syntax = was_in_fn_syntax; + } + hir::TyKind::TraitObject(bounds, ref lifetime) => { + debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + match lifetime.name { + LifetimeName::Implicit => { + // For types like `dyn Foo`, we should + // generate a special form of elided. + span_bug!(ty.span, "object-lifetime-default expected, not implict",); + } + LifetimeName::ImplicitObjectLifetimeDefault => { + // If the user does not write *anything*, we + // use the object lifetime defaulting + // rules. So e.g., `Box` becomes + // `Box`. + self.resolve_object_lifetime_default(lifetime) + } + LifetimeName::Underscore => { + // If the user writes `'_`, we use the *ordinary* elision + // rules. So the `'_` in e.g., `Box` will be + // resolved the same as the `'_` in `&'_ Foo`. + // + // cc #48468 + self.resolve_elided_lifetimes(vec![lifetime]) + } + LifetimeName::Param(_) | LifetimeName::Static => { + // If the user wrote an explicit name, use that. + self.visit_lifetime(lifetime); + } + LifetimeName::Error => {} + } + } + hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { + self.visit_lifetime(lifetime_ref); + let scope = Scope::ObjectLifetimeDefault { + lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), + s: self.scope, + }; + self.with(scope, |_, this| this.visit_ty(&mt.ty)); + } + hir::TyKind::Def(item_id, lifetimes) => { + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `type MyAnonTy<'b> = impl MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the opaque_ty generics + let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { + // Named opaque `impl Trait` types are reached via `TyKind::Path`. + // This arm is for `impl Trait` in the types of statics, constants and locals. + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { + intravisit::walk_ty(self, ty); + return; + } + // RPIT (return position impl trait) + hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, bounds, .. }) => { + (generics, bounds) + } + ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + }; + + // Resolve the lifetimes that are applied to the opaque type. + // These are resolved in the current scope. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `fn foo<'a>() -> MyAnonTy<'a> { ... }` + // ^ ^this gets resolved in the current scope + for lifetime in lifetimes { + if let hir::GenericArg::Lifetime(lifetime) = lifetime { + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.hir_id).cloned(); + if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir().get_parent_node(hir_id); + let parent_impl_id = hir::ImplItemId { hir_id: parent_id }; + let parent_trait_id = hir::TraitItemId { hir_id: parent_id }; + let krate = self.tcx.hir().krate(); + + if !(krate.items.contains_key(&parent_id) + || krate.impl_items.contains_key(&parent_impl_id) + || krate.trait_items.contains_key(&parent_trait_id)) + { + struct_span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ) + .emit(); + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } + } + } + } + } + + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut index = self.next_early_index_for_opaque_type(); + debug!("visit_ty: index = {}", index); + + let mut elision = None; + let mut lifetimes = FxHashMap::default(); + let mut non_lifetime_count = 0; + for param in generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => { + let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); + let def_id = if let Region::EarlyBound(_, def_id, _) = reg { + def_id + } else { + bug!(); + }; + if let hir::ParamName::Plain(param_name) = name { + if param_name.name == kw::UnderscoreLifetime { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); + elision = Some(reg); + } else { + lifetimes.insert(name, reg); + } + } else { + self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); + lifetimes.insert(name, reg); + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + } + } + } + let next_early_index = index + non_lifetime_count; + + if let Some(elision_region) = elision { + let scope = + Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; + self.with(scope, |_old_scope, this| { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + this.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + }); + } else { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } + } + _ => intravisit::walk_ty(self, ty), + } + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + use self::hir::TraitItemKind::*; + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); + match trait_item.kind { + Method(ref sig, _) => { + let tcx = self.tcx; + self.visit_early_late( + Some(tcx.hir().get_parent_item(trait_item.hir_id)), + &sig.decl, + &trait_item.generics, + |this| intravisit::walk_trait_item(this, trait_item), + ); + } + Type(bounds, ref ty) => { + let generics = &trait_item.generics; + let mut index = self.next_early_index(); + debug!("visit_ty: index = {}", index); + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + if let Some(ty) = ty { + this.visit_ty(ty); + } + }); + } + Const(_, _) => { + // Only methods and types support generics. + assert!(trait_item.generics.params.is_empty()); + intravisit::walk_trait_item(self, trait_item); + } + } + self.missing_named_lifetime_spots.pop(); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + use self::hir::ImplItemKind::*; + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); + match impl_item.kind { + Method(ref sig, _) => { + let tcx = self.tcx; + self.visit_early_late( + Some(tcx.hir().get_parent_item(impl_item.hir_id)), + &sig.decl, + &impl_item.generics, + |this| intravisit::walk_impl_item(this, impl_item), + ) + } + TyAlias(ref ty) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut non_lifetime_count = 0; + debug!("visit_ty: index = {}", index); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index + non_lifetime_count, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + this.visit_generics(generics); + this.visit_ty(ty); + }); + } + OpaqueTy(bounds) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut next_early_index = index; + debug!("visit_ty: index = {}", index); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + GenericParamKind::Const { .. } => { + next_early_index += 1; + None + } + }) + .collect(); + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } + Const(_, _) => { + // Only methods and types support generics. + assert!(impl_item.generics.params.is_empty()); + intravisit::walk_impl_item(self, impl_item); + } + } + self.missing_named_lifetime_spots.pop(); + } + + fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); + if lifetime_ref.is_elided() { + self.resolve_elided_lifetimes(vec![lifetime_ref]); + return; + } + if lifetime_ref.is_static() { + self.insert_lifetime(lifetime_ref, Region::Static); + return; + } + self.resolve_lifetime_ref(lifetime_ref); + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + for (i, segment) in path.segments.iter().enumerate() { + let depth = path.segments.len() - i - 1; + if let Some(ref args) = segment.args { + self.visit_segment_args(path.res, depth, args); + } + } + } + + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { + let output = match fd.output { + hir::FnRetTy::DefaultReturn(_) => None, + hir::FnRetTy::Return(ref ty) => Some(&**ty), + }; + self.visit_fn_like_elision(&fd.inputs, output); + } + + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); + for param in generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { ref default, .. } => { + walk_list!(self, visit_param_bound, param.bounds); + if let Some(ref ty) = default { + self.visit_ty(&ty); + } + } + GenericParamKind::Const { ref ty, .. } => { + walk_list!(self, visit_param_bound, param.bounds); + self.visit_ty(&ty); + } + } + } + for predicate in generics.where_clause.predicates { + match predicate { + &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + ref bounded_ty, + bounds, + ref bound_generic_params, + .. + }) => { + let lifetimes: FxHashMap<_, _> = bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(); + if !lifetimes.is_empty() { + self.trait_ref_hack = true; + let next_early_index = self.next_early_index(); + let scope = Scope::Binder { + lifetimes, + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + let result = self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &bound_generic_params); + this.visit_ty(&bounded_ty); + walk_list!(this, visit_param_bound, bounds); + }); + self.trait_ref_hack = false; + result + } else { + self.visit_ty(&bounded_ty); + walk_list!(self, visit_param_bound, bounds); + } + } + &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + ref lifetime, + bounds, + .. + }) => { + self.visit_lifetime(lifetime); + walk_list!(self, visit_param_bound, bounds); + } + &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + ref lhs_ty, + ref rhs_ty, + .. + }) => { + self.visit_ty(lhs_ty); + self.visit_ty(rhs_ty); + } + } + } + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'tcx hir::PolyTraitRef<'tcx>, + _modifier: hir::TraitBoundModifier, + ) { + debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + + let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); + if !self.trait_ref_hack + || trait_ref.bound_generic_params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }) + { + if self.trait_ref_hack { + struct_span_err!( + self.tcx.sess, + trait_ref.span, + E0316, + "nested quantification of lifetimes" + ) + .emit(); + } + let next_early_index = self.next_early_index(); + let scope = Scope::Binder { + lifetimes: trait_ref + .bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir(), param)) + } + _ => None, + }) + .collect(), + s: self.scope, + next_early_index, + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); + walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); + this.visit_trait_ref(&trait_ref.trait_ref); + }) + } else { + self.visit_trait_ref(&trait_ref.trait_ref); + } + if should_pop_missing_lt { + self.missing_named_lifetime_spots.pop(); + } + } +} + +#[derive(Copy, Clone, PartialEq)] +enum ShadowKind { + Label, + Lifetime, +} +struct Original { + kind: ShadowKind, + span: Span, +} +struct Shadower { + kind: ShadowKind, + span: Span, +} + +fn original_label(span: Span) -> Original { + Original { kind: ShadowKind::Label, span: span } +} +fn shadower_label(span: Span) -> Shadower { + Shadower { kind: ShadowKind::Label, span: span } +} +fn original_lifetime(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span: span } +} +fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { + Shadower { kind: ShadowKind::Lifetime, span: param.span } +} + +impl ShadowKind { + fn desc(&self) -> &'static str { + match *self { + ShadowKind::Label => "label", + ShadowKind::Lifetime => "lifetime", + } + } +} + +fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { + let lifetime_params: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), + _ => None, + }) + .collect(); + let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); + let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); + + if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { + struct_span_err!( + tcx.sess, + *in_band_span, + E0688, + "cannot mix in-band and explicit lifetime definitions" + ) + .span_label(*in_band_span, "in-band lifetime definition here") + .span_label(*explicit_span, "explicit lifetime definition here") + .emit(); + } +} + +fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: ast::Name, orig: Original, shadower: Shadower) { + let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { + // lifetime/lifetime shadowing is an error + struct_span_err!( + tcx.sess, + shadower.span, + E0496, + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), + name, + orig.kind.desc() + ) + } else { + // shadowing involving a label is only a warning, due to issues with + // labels and lifetimes not being macro-hygienic. + tcx.sess.struct_span_warn( + shadower.span, + &format!( + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), + name, + orig.kind.desc() + ), + ) + }; + err.span_label(orig.span, "first declared here"); + err.span_label(shadower.span, format!("lifetime {} already in scope", name)); + err.emit(); +} + +// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning +// if one of the label shadows a lifetime or another label. +fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { + struct GatherLabels<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + scope: ScopeRef<'a>, + labels_in_fn: &'a mut Vec, + } + + let mut gather = + GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; + gather.visit_body(body); + + impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { + type Map = Map<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &hir::Expr<'_>) { + if let Some(label) = expression_label(ex) { + for prior_label in &self.labels_in_fn[..] { + // FIXME (#24278): non-hygienic comparison + if label.name == prior_label.name { + signal_shadowing_problem( + self.tcx, + label.name, + original_label(prior_label.span), + shadower_label(label.span), + ); + } + } + + check_if_label_shadows_lifetime(self.tcx, self.scope, label); + + self.labels_in_fn.push(label); + } + intravisit::walk_expr(self, ex) + } + } + + fn expression_label(ex: &hir::Expr<'_>) -> Option { + if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None } + } + + fn check_if_label_shadows_lifetime( + tcx: TyCtxt<'_>, + mut scope: ScopeRef<'_>, + label: ast::Ident, + ) { + loop { + match *scope { + Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + + Scope::Root => { + return; + } + + Scope::Binder { ref lifetimes, s, .. } => { + // FIXME (#24278): non-hygienic comparison + if let Some(def) = lifetimes.get(&hir::ParamName::Plain(label.modern())) { + let hir_id = tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); + + signal_shadowing_problem( + tcx, + label.name, + original_lifetime(tcx.hir().span(hir_id)), + shadower_label(label.span), + ); + return; + } + scope = s; + } + } + } + } +} + +fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { + let mut map = HirIdMap::default(); + for item in tcx.hir().krate().items.values() { + match item.kind { + hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { + ref generics, impl_trait_fn: None, .. + }) + | hir::ItemKind::TyAlias(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(tcx, generics); + + // Debugging aid. + if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) { + let object_lifetime_default_reprs: String = result + .iter() + .map(|set| match *set { + Set1::Empty => "BaseDefault".into(), + Set1::One(Region::Static) => "'static".into(), + Set1::One(Region::EarlyBound(mut i, _, _)) => generics + .params + .iter() + .find_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if i == 0 { + return Some(param.name.ident().to_string().into()); + } + i -= 1; + None + } + _ => None, + }) + .unwrap(), + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".into(), + }) + .collect::>>() + .join(","); + tcx.sess.span_err(item.span, &object_lifetime_default_reprs); + } + + map.insert(item.hir_id, result); + } + _ => {} + } + } + map +} + +/// Scan the bounds and where-clauses on parameters to extract bounds +/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` +/// for each type parameter. +fn object_lifetime_defaults_for_item( + tcx: TyCtxt<'_>, + generics: &hir::Generics<'_>, +) -> Vec { + fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { + for bound in bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.modern()); + } + } + } + + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; + + add_bounds(&mut set, ¶m.bounds); + + let param_def_id = tcx.hir().local_def_id(param.hir_id); + for predicate in generics.where_clause.predicates { + // Look for `type: ...` where clauses. + let data = match *predicate { + hir::WherePredicate::BoundPredicate(ref data) => data, + _ => continue, + }; + + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_generic_params.is_empty() { + continue; + } + + let res = match data.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, + _ => continue, + }; + + if res == Res::Def(DefKind::TyParam, param_def_id) { + add_bounds(&mut set, &data.bounds); + } + } + + Some(match set { + Set1::Empty => Set1::Empty, + Set1::One(name) => { + if name == hir::LifetimeName::Static { + Set1::One(Region::Static) + } else { + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(( + param.hir_id, + hir::LifetimeName::Param(param.name), + LifetimeDefOrigin::from_param(param), + )), + _ => None, + }) + .enumerate() + .find(|&(_, (_, lt_name, _))| lt_name == name) + .map_or(Set1::Many, |(i, (id, _, origin))| { + let def_id = tcx.hir().local_def_id(id); + Set1::One(Region::EarlyBound(i as u32, def_id, origin)) + }) + } + } + Set1::Many => Set1::Many, + }) + } + GenericParamKind::Const { .. } => { + // Generic consts don't impose any constraints. + None + } + }) + .collect() +} + +impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { + // FIXME(#37666) this works around a limitation in the region inferencer + fn hack(&mut self, f: F) + where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + f(self) + } + + fn with(&mut self, wrap_scope: Scope<'_>, f: F) + where + F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), + { + let LifetimeContext { tcx, map, lifetime_uses, .. } = self; + let labels_in_fn = take(&mut self.labels_in_fn); + let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); + let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); + let mut this = LifetimeContext { + tcx: *tcx, + map: map, + scope: &wrap_scope, + trait_ref_hack: self.trait_ref_hack, + is_in_fn_syntax: self.is_in_fn_syntax, + labels_in_fn, + xcrate_object_lifetime_defaults, + lifetime_uses, + missing_named_lifetime_spots, + }; + debug!("entering scope {:?}", this.scope); + f(self.scope, &mut this); + this.check_uses_for_lifetimes_defined_by_scope(); + debug!("exiting scope {:?}", this.scope); + self.labels_in_fn = this.labels_in_fn; + self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; + self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; + } + + /// helper method to determine the span to remove when suggesting the + /// deletion of a lifetime + fn lifetime_deletion_span( + &self, + name: ast::Ident, + generics: &hir::Generics<'_>, + ) -> Option { + generics.params.iter().enumerate().find_map(|(i, param)| { + if param.name.ident() == name { + let mut in_band = false; + if let hir::GenericParamKind::Lifetime { kind } = param.kind { + if let hir::LifetimeParamKind::InBand = kind { + in_band = true; + } + } + if in_band { + Some(param.span) + } else { + if generics.params.len() == 1 { + // if sole lifetime, remove the entire `<>` brackets + Some(generics.span) + } else { + // if removing within `<>` brackets, we also want to + // delete a leading or trailing comma as appropriate + if i >= generics.params.len() - 1 { + Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) + } else { + Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) + } + } + } + } else { + None + } + }) + } + + // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)` + // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` + fn suggest_eliding_single_use_lifetime( + &self, + err: &mut DiagnosticBuilder<'_>, + def_id: DefId, + lifetime: &hir::Lifetime, + ) { + let name = lifetime.name.ident(); + let mut remove_decl = None; + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { + remove_decl = self.lifetime_deletion_span(name, generics); + } + } + + let mut remove_use = None; + let mut elide_use = None; + let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| { + for input in inputs { + match input.kind { + hir::TyKind::Rptr(lt, _) => { + if lt.name.ident() == name { + // include the trailing whitespace between the lifetime and type names + let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi()); + remove_use = Some( + self.tcx + .sess + .source_map() + .span_until_non_whitespace(lt_through_ty_span), + ); + break; + } + } + hir::TyKind::Path(ref qpath) => { + if let QPath::Resolved(_, path) = qpath { + let last_segment = &path.segments[path.segments.len() - 1]; + let generics = last_segment.generic_args(); + for arg in generics.args.iter() { + if let GenericArg::Lifetime(lt) = arg { + if lt.name.ident() == name { + elide_use = Some(lt.span); + break; + } + } + } + break; + } + } + _ => {} + } + } + }; + if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) { + if let Some(parent) = + self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id)) + { + match parent { + Node::Item(item) => { + if let hir::ItemKind::Fn(sig, _, _) = &item.kind { + find_arg_use_span(sig.decl.inputs); + } + } + Node::ImplItem(impl_item) => { + if let hir::ImplItemKind::Method(sig, _) = &impl_item.kind { + find_arg_use_span(sig.decl.inputs); + } + } + _ => {} + } + } + } + + let msg = "elide the single-use lifetime"; + match (remove_decl, remove_use, elide_use) { + (Some(decl_span), Some(use_span), None) => { + // if both declaration and use deletion spans start at the same + // place ("start at" because the latter includes trailing + // whitespace), then this is an in-band lifetime + if decl_span.shrink_to_lo() == use_span.shrink_to_lo() { + err.span_suggestion( + use_span, + msg, + String::new(), + Applicability::MachineApplicable, + ); + } else { + err.multipart_suggestion( + msg, + vec![(decl_span, String::new()), (use_span, String::new())], + Applicability::MachineApplicable, + ); + } + } + (Some(decl_span), None, Some(use_span)) => { + err.multipart_suggestion( + msg, + vec![(decl_span, String::new()), (use_span, "'_".to_owned())], + Applicability::MachineApplicable, + ); + } + _ => {} + } + } + + fn check_uses_for_lifetimes_defined_by_scope(&mut self) { + let defined_by = match self.scope { + Scope::Binder { lifetimes, .. } => lifetimes, + _ => { + debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); + return; + } + }; + + let mut def_ids: Vec<_> = defined_by + .values() + .flat_map(|region| match region { + Region::EarlyBound(_, def_id, _) + | Region::LateBound(_, def_id, _) + | Region::Free(_, def_id) => Some(*def_id), + + Region::LateBoundAnon(..) | Region::Static => None, + }) + .collect(); + + // ensure that we issue lints in a repeatable order + def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); + + for def_id in def_ids { + debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); + + let lifetimeuseset = self.lifetime_uses.remove(&def_id); + + debug!( + "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", + lifetimeuseset + ); + + match lifetimeuseset { + Some(LifetimeUseSet::One(lifetime)) => { + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + debug!("hir id first={:?}", hir_id); + if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.hir_id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), + Node::GenericParam(param) => { + Some((param.hir_id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id = {:?} span = {:?} name = {:?}", id, span, name); + if name.name == kw::UnderscoreLifetime { + continue; + } + + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(parent_hir_id) = + self.tcx.hir().as_local_hir_id(parent_def_id) + { + // lifetimes in `derive` expansions don't count (Issue #53738) + if self + .tcx + .hir() + .attrs(parent_hir_id) + .iter() + .any(|attr| attr.check_name(sym::automatically_derived)) + { + continue; + } + } + } + + self.tcx.struct_span_lint_hir( + lint::builtin::SINGLE_USE_LIFETIMES, + id, + span, + |lint| { + let mut err = lint.build(&format!( + "lifetime parameter `{}` only used once", + name + )); + if span == lifetime.span { + // spans are the same for in-band lifetime declarations + err.span_label(span, "this lifetime is only used here"); + } else { + err.span_label(span, "this lifetime..."); + err.span_label(lifetime.span, "...is used only here"); + } + self.suggest_eliding_single_use_lifetime( + &mut err, def_id, lifetime, + ); + err.emit(); + }, + ); + } + } + Some(LifetimeUseSet::Many) => { + debug!("not one use lifetime"); + } + None => { + let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.hir_id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), + Node::GenericParam(param) => { + Some((param.hir_id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id ={:?} span = {:?} name = {:?}", id, span, name); + self.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_LIFETIMES, + id, + span, + |lint| { + let mut err = lint + .build(&format!("lifetime parameter `{}` never used", name)); + if let Some(parent_def_id) = self.tcx.parent(def_id) { + if let Some(generics) = + self.tcx.hir().get_generics(parent_def_id) + { + let unused_lt_span = + self.lifetime_deletion_span(name, generics); + if let Some(span) = unused_lt_span { + err.span_suggestion( + span, + "elide the unused lifetime", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } + err.emit(); + }, + ); + } + } + } + } + } + + /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. + /// + /// Handles visiting fns and methods. These are a bit complicated because we must distinguish + /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear + /// within type bounds; those are early bound lifetimes, and the rest are late bound. + /// + /// For example: + /// + /// fn foo<'a,'b,'c,T:Trait<'b>>(...) + /// + /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound + /// lifetimes may be interspersed together. + /// + /// If early bound lifetimes are present, we separate them into their own list (and likewise + /// for late bound). They will be numbered sequentially, starting from the lowest index that is + /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late + /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the + /// ordering is not important there. + fn visit_early_late( + &mut self, + parent_id: Option, + decl: &'tcx hir::FnDecl<'tcx>, + generics: &'tcx hir::Generics<'tcx>, + walk: F, + ) where + F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), + { + insert_late_bound_lifetimes(self.map, decl, generics); + + // Find the start of nested early scopes, e.g., in methods. + let mut index = 0; + if let Some(parent_id) = parent_id { + let parent = self.tcx.hir().expect_item(parent_id); + if sub_items_have_self_param(&parent.kind) { + index += 1; // Self comes before lifetimes + } + match parent.kind { + hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::Impl { ref generics, .. } => { + index += generics.params.len() as u32; + } + _ => {} + } + } + + let mut non_lifetime_count = 0; + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.map.late_bound.contains(¶m.hir_id) { + Some(Region::late(&self.tcx.hir(), param)) + } else { + Some(Region::early(&self.tcx.hir(), &mut index, param)) + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + non_lifetime_count += 1; + None + } + }) + .collect(); + let next_early_index = index + non_lifetime_count; + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + opaque_type_parent: true, + track_lifetime_uses: false, + }; + self.with(scope, move |old_scope, this| { + this.check_lifetime_params(old_scope, &generics.params); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` + }); + } + + fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => return 0, + + Scope::Binder { next_early_index, opaque_type_parent, .. } + if (!only_opaque_type_parent || opaque_type_parent) => + { + return next_early_index; + } + + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => scope = s, + } + } + } + + /// Returns the next index one would use for an early-bound-region + /// if extending the current scope. + fn next_early_index(&self) -> u32 { + self.next_early_index_helper(true) + } + + /// Returns the next index one would use for an `impl Trait` that + /// is being converted into an opaque type alias `impl Trait`. This will be the + /// next early index from the enclosing item, for the most + /// part. See the `opaque_type_parent` field for more info. + fn next_early_index_for_opaque_type(&self) -> u32 { + self.next_early_index_helper(false) + } + + fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); + + // If we've already reported an error, just ignore `lifetime_ref`. + if let LifetimeName::Error = lifetime_ref.name { + return; + } + + // Walk up the scope chain, tracking the number of fn scopes + // that we pass through, until we find a lifetime with the + // given name or we run out of scopes. + // search. + let mut late_depth = 0; + let mut scope = self.scope; + let mut outermost_body = None; + let result = loop { + match *scope { + Scope::Body { id, s } => { + outermost_body = Some(id); + scope = s; + } + + Scope::Root => { + break None; + } + + Scope::Binder { ref lifetimes, s, .. } => { + match lifetime_ref.name { + LifetimeName::Param(param_name) => { + if let Some(&def) = lifetimes.get(¶m_name.modern()) { + break Some(def.shifted(late_depth)); + } + } + _ => bug!("expected LifetimeName::Param"), + } + + late_depth += 1; + scope = s; + } + + Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + }; + + if let Some(mut def) = result { + if let Region::EarlyBound(..) = def { + // Do not free early-bound regions, only late-bound ones. + } else if let Some(body_id) = outermost_body { + let fn_id = self.tcx.hir().body_owner(body_id); + match self.tcx.hir().get(fn_id) { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Method(..), + .. + }) + | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Method(..), .. + }) => { + let scope = self.tcx.hir().local_def_id(fn_id); + def = Region::Free(scope, def.id().unwrap()); + } + _ => {} + } + } + + // Check for fn-syntax conflicts with in-band lifetime definitions + if self.is_in_fn_syntax { + match def { + Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) + | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { + struct_span_err!( + self.tcx.sess, + lifetime_ref.span, + E0687, + "lifetimes used in `fn` or `Fn` syntax must be \ + explicitly declared using `<...>` binders" + ) + .span_label(lifetime_ref.span, "in-band lifetime definition") + .emit(); + } + + Region::Static + | Region::EarlyBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::LateBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::EarlyBound(_, _, LifetimeDefOrigin::Error) + | Region::LateBound(_, _, LifetimeDefOrigin::Error) + | Region::LateBoundAnon(..) + | Region::Free(..) => {} + } + } + + self.insert_lifetime(lifetime_ref, def); + } else { + self.emit_undeclared_lifetime_error(lifetime_ref); + } + } + + fn visit_segment_args( + &mut self, + res: Res, + depth: usize, + generic_args: &'tcx hir::GenericArgs<'tcx>, + ) { + debug!( + "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", + res, depth, generic_args, + ); + + if generic_args.parenthesized { + let was_in_fn_syntax = self.is_in_fn_syntax; + self.is_in_fn_syntax = true; + self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); + self.is_in_fn_syntax = was_in_fn_syntax; + return; + } + + let mut elide_lifetimes = true; + let lifetimes = generic_args + .args + .iter() + .filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + Some(lt) + } + _ => None, + }) + .collect(); + if elide_lifetimes { + self.resolve_elided_lifetimes(lifetimes); + } else { + lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); + } + + // Figure out if this is a type/trait segment, + // which requires object lifetime defaults. + let parent_def_id = |this: &mut Self, def_id: DefId| { + let def_key = this.tcx.def_key(def_id); + DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } + }; + let type_def_id = match res { + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::Struct, def_id) + | Res::Def(DefKind::Union, def_id) + | Res::Def(DefKind::Enum, def_id) + | Res::Def(DefKind::TyAlias, def_id) + | Res::Def(DefKind::Trait, def_id) + if depth == 0 => + { + Some(def_id) + } + _ => None, + }; + + debug!("visit_segment_args: type_def_id={:?}", type_def_id); + + // Compute a vector of defaults, one for each type parameter, + // per the rules given in RFCs 599 and 1156. Example: + // + // ```rust + // struct Foo<'a, T: 'a, U> { } + // ``` + // + // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default + // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) + // and `dyn Baz` to `dyn Baz + 'static` (because there is no + // such bound). + // + // Therefore, we would compute `object_lifetime_defaults` to a + // vector like `['x, 'static]`. Note that the vector only + // includes type parameters. + let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { + let in_body = { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + Scope::Body { .. } => break true, + + Scope::Binder { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + } + }; + + let map = &self.map; + let unsubst = if let Some(id) = self.tcx.hir().as_local_hir_id(def_id) { + &map.object_lifetime_defaults[&id] + } else { + let tcx = self.tcx; + self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { + tcx.generics_of(def_id) + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, + }) + .collect() + }) + }; + debug!("visit_segment_args: unsubst={:?}", unsubst); + unsubst + .iter() + .map(|set| match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(r) => { + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + r.subst(lifetimes, map) + } + Set1::Many => None, + }) + .collect() + }); + + debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); + + let mut i = 0; + for arg in generic_args.args { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; + self.with(scope, |_, this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + i += 1; + } + GenericArg::Const(ct) => { + self.visit_anon_const(&ct.value); + } + } + } + + // Hack: when resolving the type `XX` in binding like `dyn + // Foo<'b, Item = XX>`, the current object-lifetime default + // would be to examine the trait `Foo` to check whether it has + // a lifetime bound declared on `Item`. e.g., if `Foo` is + // declared like so, then the default object lifetime bound in + // `XX` should be `'b`: + // + // ```rust + // trait Foo<'a> { + // type Item: 'a; + // } + // ``` + // + // but if we just have `type Item;`, then it would be + // `'static`. However, we don't get all of this logic correct. + // + // Instead, we do something hacky: if there are no lifetime parameters + // to the trait, then we simply use a default object lifetime + // bound of `'static`, because there is no other possibility. On the other hand, + // if there ARE lifetime parameters, then we require the user to give an + // explicit bound for now. + // + // This is intended to leave room for us to implement the + // correct behavior in the future. + let has_lifetime_parameter = generic_args.args.iter().any(|arg| match arg { + GenericArg::Lifetime(_) => true, + _ => false, + }); + + // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. + for b in generic_args.bindings { + let scope = Scope::ObjectLifetimeDefault { + lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, + s: self.scope, + }; + self.with(scope, |_, this| this.visit_assoc_type_binding(b)); + } + } + + fn visit_fn_like_elision( + &mut self, + inputs: &'tcx [hir::Ty<'tcx>], + output: Option<&'tcx hir::Ty<'tcx>>, + ) { + debug!("visit_fn_like_elision: enter"); + let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); + let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope }; + self.with(arg_scope, |_, this| { + for input in inputs { + this.visit_ty(input); + } + match *this.scope { + Scope::Elision { ref elide, .. } => { + arg_elide = elide.clone(); + } + _ => bug!(), + } + }); + + let output = match output { + Some(ty) => ty, + None => return, + }; + + debug!("visit_fn_like_elision: determine output"); + + // Figure out if there's a body we can get argument names from, + // and whether there's a `self` argument (treated specially). + let mut assoc_item_kind = None; + let mut impl_self = None; + let parent = self.tcx.hir().get_parent_node(output.hir_id); + let body = match self.tcx.hir().get(parent) { + // `fn` definitions and methods. + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), + + Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Method(_, ref m), .. + }) => { + if let hir::ItemKind::Trait(.., ref trait_items) = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + assoc_item_kind = + trait_items.iter().find(|ti| ti.id.hir_id == parent).map(|ti| ti.kind); + } + match *m { + hir::TraitMethod::Required(_) => None, + hir::TraitMethod::Provided(body) => Some(body), + } + } + + Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Method(_, body), .. }) => { + if let hir::ItemKind::Impl { ref self_ty, ref items, .. } = + self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind + { + impl_self = Some(self_ty); + assoc_item_kind = + items.iter().find(|ii| ii.id.hir_id == parent).map(|ii| ii.kind); + } + Some(body) + } + + // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). + Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, + // Everything else (only closures?) doesn't + // actually enjoy elision in return types. + _ => { + self.visit_ty(output); + return; + } + }; + + let has_self = match assoc_item_kind { + Some(hir::AssocItemKind::Method { has_self }) => has_self, + _ => false, + }; + + // In accordance with the rules for lifetime elision, we can determine + // what region to use for elision in the output type in two ways. + // First (determined here), if `self` is by-reference, then the + // implied output region is the region of the self parameter. + if has_self { + struct SelfVisitor<'a> { + map: &'a NamedRegionMap, + impl_self: Option<&'a hir::TyKind<'a>>, + lifetime: Set1, + } + + impl SelfVisitor<'_> { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + fn is_self_ty(&self, res: Res) -> bool { + if let Res::SelfTy(..) = res { + return true; + } + + // Can't always rely on literal (or implied) `Self` due + // to the way elision rules were originally specified. + if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = + self.impl_self + { + match path.res { + // Whitelist the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Enum, _) + | Res::PrimTy(_) => return res == path.res, + _ => {} + } + } + + false + } + } + + impl<'a> Visitor<'a> for SelfVisitor<'a> { + type Map = Map<'a>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { + if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind + { + if self.is_self_ty(path.res) { + if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + self.lifetime.insert(*lifetime); + } + } + } + } + intravisit::walk_ty(self, ty) + } + } + + let mut visitor = SelfVisitor { + map: self.map, + impl_self: impl_self.map(|ty| &ty.kind), + lifetime: Set1::Empty, + }; + visitor.visit_ty(&inputs[0]); + if let Set1::One(lifetime) = visitor.lifetime { + let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; + self.with(scope, |_, this| this.visit_ty(output)); + return; + } + } + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let mut possible_implied_output_region = None; + let mut lifetime_count = 0; + let arg_lifetimes = inputs + .iter() + .enumerate() + .skip(has_self as usize) + .map(|(i, input)| { + let mut gather = GatherLifetimes { + map: self.map, + outer_index: ty::INNERMOST, + have_bound_regions: false, + lifetimes: Default::default(), + }; + gather.visit_ty(input); + + lifetime_count += gather.lifetimes.len(); + + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + + ElisionFailureInfo { + parent: body, + index: i, + lifetime_count: gather.lifetimes.len(), + have_bound_regions: gather.have_bound_regions, + span: input.span, + } + }) + .collect(); + + let elide = if lifetime_count == 1 { + Elide::Exact(possible_implied_output_region.unwrap()) + } else { + Elide::Error(arg_lifetimes) + }; + + debug!("visit_fn_like_elision: elide={:?}", elide); + + let scope = Scope::Elision { elide, s: self.scope }; + self.with(scope, |_, this| this.visit_ty(output)); + debug!("visit_fn_like_elision: exit"); + + struct GatherLifetimes<'a> { + map: &'a NamedRegionMap, + outer_index: ty::DebruijnIndex, + have_bound_regions: bool, + lifetimes: FxHashSet, + } + + impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { + type Map = Map<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_in(1); + } + match ty.kind { + hir::TyKind::TraitObject(bounds, ref lifetime) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } + _ => { + intravisit::walk_ty(self, ty); + } + } + if let hir::TyKind::BareFn(_) = ty.kind { + self.outer_index.shift_out(1); + } + } + + fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + // FIXME(eddyb) Do we want this? It only makes a difference + // if this `for<'a>` lifetime parameter is never used. + self.have_bound_regions = true; + } + + intravisit::walk_generic_param(self, param); + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &hir::PolyTraitRef<'_>, + modifier: hir::TraitBoundModifier, + ) { + self.outer_index.shift_in(1); + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.outer_index.shift_out(1); + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { + match lifetime { + Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) + if debruijn < self.outer_index => + { + self.have_bound_regions = true; + } + _ => { + self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); + } + } + } + } + } + } + + fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { + debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); + + if lifetime_refs.is_empty() { + return; + } + + let span = lifetime_refs[0].span; + let mut late_depth = 0; + let mut scope = self.scope; + let mut lifetime_names = FxHashSet::default(); + let error = loop { + match *scope { + // Do not assign any resolution, it will be inferred. + Scope::Body { .. } => return, + + Scope::Root => break None, + + Scope::Binder { s, ref lifetimes, .. } => { + // collect named lifetimes for suggestions + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } + late_depth += 1; + scope = s; + } + + Scope::Elision { ref elide, ref s, .. } => { + let lifetime = match *elide { + Elide::FreshLateAnon(ref counter) => { + for lifetime_ref in lifetime_refs { + let lifetime = Region::late_anon(counter).shifted(late_depth); + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + Elide::Exact(l) => l.shifted(late_depth), + Elide::Error(ref e) => { + if let Scope::Binder { ref lifetimes, .. } = s { + // collect named lifetimes for suggestions + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } + } + break Some(e); + } + }; + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + + Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + }; + + let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); + let mut add_label = true; + + if let Some(params) = error { + if lifetime_refs.len() == 1 { + add_label = add_label && self.report_elision_failure(&mut err, params, span); + } + } + if add_label { + self.add_missing_lifetime_specifiers_label( + &mut err, + span, + lifetime_refs.len(), + &lifetime_names, + error.map(|p| &p[..]).unwrap_or(&[]), + ); + } + + err.emit(); + } + + fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { + match self.tcx.sess.source_map().span_to_snippet(span) { + Ok(ref snippet) => { + let (sugg, applicability) = if snippet == "&" { + ("&'static ".to_owned(), Applicability::MachineApplicable) + } else if snippet == "'_" { + ("'static".to_owned(), Applicability::MachineApplicable) + } else { + (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) + }; + db.span_suggestion(span, msg, sugg, applicability); + false + } + Err(_) => { + db.help(msg); + true + } + } + } + + fn report_elision_failure( + &mut self, + db: &mut DiagnosticBuilder<'_>, + params: &[ElisionFailureInfo], + span: Span, + ) -> bool { + let mut m = String::new(); + let len = params.len(); + + let elided_params: Vec<_> = + params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = + info; + + db.span_label(span, ""); + let help_name = if let Some(ident) = + parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) + { + format!("`{}`", ident) + } else { + format!("argument {}", index + 1) + }; + + m.push_str( + &(if n == 1 { + help_name + } else { + format!( + "one of {}'s {} {}lifetimes", + help_name, + n, + if have_bound_regions { "free " } else { "" } + ) + })[..], + ); + + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); + } + } + + if len == 0 { + db.help( + "this function's return type contains a borrowed value, \ + but there is no value for it to be borrowed from", + ); + self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") + } else if elided_len == 0 { + db.help( + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments", + ); + let msg = "consider giving it an explicit bounded or 'static lifetime"; + self.suggest_lifetime(db, span, msg) + } else if elided_len == 1 { + db.help(&format!( + "this function's return type contains a borrowed value, \ + but the signature does not say which {} it is borrowed from", + m + )); + true + } else { + db.help(&format!( + "this function's return type contains a borrowed value, \ + but the signature does not say whether it is borrowed from {}", + m + )); + true + } + } + + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); + let mut late_depth = 0; + let mut scope = self.scope; + let lifetime = loop { + match *scope { + Scope::Binder { s, .. } => { + late_depth += 1; + scope = s; + } + + Scope::Root | Scope::Elision { .. } => break Region::Static, + + Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, + + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + } + }; + self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + } + + fn check_lifetime_params( + &mut self, + old_scope: ScopeRef<'_>, + params: &'tcx [hir::GenericParam<'tcx>], + ) { + let lifetimes: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), + _ => None, + }) + .collect(); + for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { + if let hir::ParamName::Plain(_) = lifetime_i_name { + let name = lifetime_i_name.ident().name; + if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_i.span, + E0262, + "invalid lifetime parameter name: `{}`", + lifetime_i.name.ident(), + ); + err.span_label( + lifetime_i.span, + format!("{} is a reserved lifetime name", name), + ); + err.emit(); + } + } + + // It is a hard error to shadow a lifetime within the same scope. + for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { + if lifetime_i_name == lifetime_j_name { + struct_span_err!( + self.tcx.sess, + lifetime_j.span, + E0263, + "lifetime name `{}` declared twice in the same scope", + lifetime_j.name.ident() + ) + .span_label(lifetime_j.span, "declared twice") + .span_label(lifetime_i.span, "previous declaration here") + .emit(); + } + } + + // It is a soft error to shadow a lifetime within a parent scope. + self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); + + for bound in lifetime_i.bounds { + match bound { + hir::GenericBound::Outlives(ref lt) => match lt.name { + hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( + lt.span, + "use of `'_` in illegal place, but not caught by lowering", + ), + hir::LifetimeName::Static => { + self.insert_lifetime(lt, Region::Static); + self.tcx + .sess + .struct_span_warn( + lifetime_i.span.to(lt.span), + &format!( + "unnecessary lifetime parameter `{}`", + lifetime_i.name.ident(), + ), + ) + .help(&format!( + "you can use the `'static` lifetime directly, in place of `{}`", + lifetime_i.name.ident(), + )) + .emit(); + } + hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { + self.resolve_lifetime_ref(lt); + } + hir::LifetimeName::ImplicitObjectLifetimeDefault => { + self.tcx.sess.delay_span_bug( + lt.span, + "lowering generated `ImplicitObjectLifetimeDefault` \ + outside of an object type", + ) + } + hir::LifetimeName::Error => { + // No need to do anything, error already reported. + } + }, + _ => bug!(), + } + } + } + } + + fn check_lifetime_param_for_shadowing( + &self, + mut old_scope: ScopeRef<'_>, + param: &'tcx hir::GenericParam<'tcx>, + ) { + for label in &self.labels_in_fn { + // FIXME (#24278): non-hygienic comparison + if param.name.ident().name == label.name { + signal_shadowing_problem( + self.tcx, + label.name, + original_label(label.span), + shadower_lifetime(¶m), + ); + return; + } + } + + loop { + match *old_scope { + Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } => { + old_scope = s; + } + + Scope::Root => { + return; + } + + Scope::Binder { ref lifetimes, s, .. } => { + if let Some(&def) = lifetimes.get(¶m.name.modern()) { + let hir_id = self.tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); + + signal_shadowing_problem( + self.tcx, + param.name.ident().name, + original_lifetime(self.tcx.hir().span(hir_id)), + shadower_lifetime(¶m), + ); + return; + } + + old_scope = s; + } + } + } + } + + /// Returns `true` if, in the current scope, replacing `'_` would be + /// equivalent to a single-use lifetime. + fn track_lifetime_uses(&self) -> bool { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + // Inside of items, it depends on the kind of item. + Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses, + + // Inside a body, `'_` will use an inference variable, + // should be fine. + Scope::Body { .. } => break true, + + // A lifetime only used in a fn argument could as well + // be replaced with `'_`, as that would generate a + // fresh name, too. + Scope::Elision { elide: Elide::FreshLateAnon(_), .. } => break true, + + // In the return type or other such place, `'_` is not + // going to make a fresh name, so we cannot + // necessarily replace a single-use lifetime with + // `'_`. + Scope::Elision { elide: Elide::Exact(_), .. } => break false, + Scope::Elision { elide: Elide::Error(_), .. } => break false, + + Scope::ObjectLifetimeDefault { s, .. } => scope = s, + } + } + } + + fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { + if lifetime_ref.hir_id == hir::DUMMY_HIR_ID { + span_bug!( + lifetime_ref.span, + "lifetime reference not renumbered, \ + probably a bug in syntax::fold" + ); + } + + debug!( + "insert_lifetime: {} resolved to {:?} span={:?}", + self.tcx.hir().node_to_string(lifetime_ref.hir_id), + def, + self.tcx.sess.source_map().span_to_string(lifetime_ref.span) + ); + self.map.defs.insert(lifetime_ref.hir_id, def); + + match def { + Region::LateBoundAnon(..) | Region::Static => { + // These are anonymous lifetimes or lifetimes that are not declared. + } + + Region::Free(_, def_id) + | Region::LateBound(_, def_id, _) + | Region::EarlyBound(_, def_id, _) => { + // A lifetime declared by the user. + let track_lifetime_uses = self.track_lifetime_uses(); + debug!("insert_lifetime: track_lifetime_uses={}", track_lifetime_uses); + if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { + debug!("insert_lifetime: first use of {:?}", def_id); + self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); + } else { + debug!("insert_lifetime: many uses of {:?}", def_id); + self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); + } + } + } + } + + /// Sometimes we resolve a lifetime, but later find that it is an + /// error (esp. around impl trait). In that case, we remove the + /// entry into `map.defs` so as not to confuse later code. + fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { + let old_value = self.map.defs.remove(&lifetime_ref.hir_id); + assert_eq!(old_value, Some(bad_def)); + } +} + +/// Detects late-bound lifetimes and inserts them into +/// `map.late_bound`. +/// +/// A region declared on a fn is **late-bound** if: +/// - it is constrained by an argument type; +/// - it does not appear in a where-clause. +/// +/// "Constrained" basically means that it appears in any type but +/// not amongst the inputs to a projection. In other words, `<&'a +/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. +fn insert_late_bound_lifetimes( + map: &mut NamedRegionMap, + decl: &hir::FnDecl<'_>, + generics: &hir::Generics<'_>, +) { + debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); + + let mut constrained_by_input = ConstrainedCollector::default(); + for arg_ty in decl.inputs { + constrained_by_input.visit_ty(arg_ty); + } + + let mut appears_in_output = AllCollector::default(); + intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); + + debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions); + + // Walk the lifetimes that appear in where clauses. + // + // Subtle point: because we disallow nested bindings, we can just + // ignore binders here and scrape up all names we see. + let mut appears_in_where_clause = AllCollector::default(); + appears_in_where_clause.visit_generics(generics); + + for param in generics.params { + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + if !param.bounds.is_empty() { + // `'a: 'b` means both `'a` and `'b` are referenced + appears_in_where_clause + .regions + .insert(hir::LifetimeName::Param(param.name.modern())); + } + } + } + + debug!( + "insert_late_bound_lifetimes: appears_in_where_clause={:?}", + appears_in_where_clause.regions + ); + + // Late bound regions are those that: + // - appear in the inputs + // - do not appear in the where-clauses + // - are not implicitly captured by `impl Trait` + for param in generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } + + // Neither types nor consts are late-bound. + hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, + } + + let lt_name = hir::LifetimeName::Param(param.name.modern()); + // appears in the where clauses? early-bound. + if appears_in_where_clause.regions.contains(<_name) { + continue; + } + + // does not appear in the inputs, but appears in the return type? early-bound. + if !constrained_by_input.regions.contains(<_name) + && appears_in_output.regions.contains(<_name) + { + continue; + } + + debug!( + "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", + param.name.ident(), + param.hir_id + ); + + let inserted = map.late_bound.insert(param.hir_id); + assert!(inserted, "visited lifetime {:?} twice", param.hir_id); + } + + return; + + #[derive(Default)] + struct ConstrainedCollector { + regions: FxHashSet, + } + + impl<'v> Visitor<'v> for ConstrainedCollector { + type Map = Map<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) + | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { + // ignore lifetimes appearing in associated type + // projections, as they are not *constrained* + // (defined above) + } + + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + // consider only the lifetimes on the final + // segment; I am not sure it's even currently + // valid to have them elsewhere, but even if it + // is, those would be potentially inputs to + // projections + if let Some(last_segment) = path.segments.last() { + self.visit_path_segment(path.span, last_segment); + } + } + + _ => { + intravisit::walk_ty(self, ty); + } + } + } + + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + self.regions.insert(lifetime_ref.name.modern()); + } + } + + #[derive(Default)] + struct AllCollector { + regions: FxHashSet, + } + + impl<'v> Visitor<'v> for AllCollector { + type Map = Map<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + NestedVisitorMap::None + } + + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + self.regions.insert(lifetime_ref.name.modern()); + } + } +} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4278bf867f3..ebd3f8b832b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -68,7 +68,6 @@ mod def_collector; mod diagnostics; mod imports; mod late; -mod lifetimes; mod macros; enum Weak { @@ -2959,5 +2958,5 @@ impl CrateLint { } pub fn provide(providers: &mut Providers<'_>) { - lifetimes::provide(providers); + late::lifetimes::provide(providers); } diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs deleted file mode 100644 index b9c5f4992f6..00000000000 --- a/src/librustc_resolve/lifetimes.rs +++ /dev/null @@ -1,2911 +0,0 @@ -//! Name resolution for lifetimes. -//! -//! Name resolution for lifetimes follows *much* simpler rules than the -//! full resolve. For example, lifetime names are never exported or -//! used between functions, and they operate in a purely top-down -//! way. Therefore, we break lifetime name resolution into a separate pass. - -use crate::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; -use rustc::hir::map::Map; -use rustc::lint; -use rustc::middle::resolve_lifetime::*; -use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; -use rustc::{bug, span_bug}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; -use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind}; -use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; -use std::borrow::Cow; -use std::cell::Cell; -use std::mem::{replace, take}; -use syntax::ast; -use syntax::attr; -use syntax::walk_list; - -use log::debug; - -// This counts the no of times a lifetime is used -#[derive(Clone, Copy, Debug)] -pub enum LifetimeUseSet<'tcx> { - One(&'tcx hir::Lifetime), - Many, -} - -trait RegionExt { - fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); - - fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); - - fn late_anon(index: &Cell) -> Region; - - fn id(&self) -> Option; - - fn shifted(self, amount: u32) -> Region; - - fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; - - fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option - where - L: Iterator; -} - -impl RegionExt for Region { - fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { - let i = *index; - *index += 1; - let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); - debug!("Region::early: index={} def_id={:?}", i, def_id); - (param.name.modern(), Region::EarlyBound(i, def_id, origin)) - } - - fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { - let depth = ty::INNERMOST; - let def_id = hir_map.local_def_id(param.hir_id); - let origin = LifetimeDefOrigin::from_param(param); - debug!( - "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", - param, depth, def_id, origin, - ); - (param.name.modern(), Region::LateBound(depth, def_id, origin)) - } - - fn late_anon(index: &Cell) -> Region { - let i = index.get(); - index.set(i + 1); - let depth = ty::INNERMOST; - Region::LateBoundAnon(depth, i) - } - - fn id(&self) -> Option { - match *self { - Region::Static | Region::LateBoundAnon(..) => None, - - Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => { - Some(id) - } - } - } - - fn shifted(self, amount: u32) -> Region { - match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_in(amount), id, origin) - } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_in(amount), index) - } - _ => self, - } - } - - fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { - match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) - } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) - } - _ => self, - } - } - - fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where - L: Iterator, - { - if let Region::EarlyBound(index, _, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) - } else { - Some(self) - } - } -} - -/// Maps the id of each lifetime reference to the lifetime decl -/// that it corresponds to. -/// -/// FIXME. This struct gets converted to a `ResolveLifetimes` for -/// actual use. It has the same data, but indexed by `DefIndex`. This -/// is silly. -#[derive(Default)] -struct NamedRegionMap { - // maps from every use of a named (not anonymous) lifetime to a - // `Region` describing how that region is bound - defs: HirIdMap, - - // the set of lifetime def ids that are late-bound; a region can - // be late-bound if (a) it does NOT appear in a where-clause and - // (b) it DOES appear in the arguments. - late_bound: HirIdSet, - - // For each type and trait definition, maps type parameters - // to the trait object lifetime defaults computed from them. - object_lifetime_defaults: HirIdMap>, -} - -crate struct LifetimeContext<'a, 'tcx> { - crate tcx: TyCtxt<'tcx>, - map: &'a mut NamedRegionMap, - scope: ScopeRef<'a>, - - /// This is slightly complicated. Our representation for poly-trait-refs contains a single - /// binder and thus we only allow a single level of quantification. However, - /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` - /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the De Bruijn indices - /// correct when representing these constraints, we should only introduce one - /// scope. However, we want to support both locations for the quantifier and - /// during lifetime resolution we want precise information (so we can't - /// desugar in an earlier phase). - /// - /// So, if we encounter a quantifier at the outer scope, we set - /// `trait_ref_hack` to `true` (and introduce a scope), and then if we encounter - /// a quantifier at the inner scope, we error. If `trait_ref_hack` is `false`, - /// then we introduce the scope at the inner quantifier. - trait_ref_hack: bool, - - /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. - is_in_fn_syntax: bool, - - /// List of labels in the function/method currently under analysis. - labels_in_fn: Vec, - - /// Cache for cross-crate per-definition object lifetime defaults. - xcrate_object_lifetime_defaults: DefIdMap>, - - lifetime_uses: &'a mut DefIdMap>, - - /// When encountering an undefined named lifetime, we will suggest introducing it in these - /// places. - crate missing_named_lifetime_spots: Vec>, -} - -#[derive(Debug)] -enum Scope<'a> { - /// Declares lifetimes, and each can be early-bound or late-bound. - /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and - /// it should be shifted by the number of `Binder`s in between the - /// declaration `Binder` and the location it's referenced from. - Binder { - lifetimes: FxHashMap, - - /// if we extend this scope with another scope, what is the next index - /// we should use for an early-bound region? - next_early_index: u32, - - /// Flag is set to true if, in this binder, `'_` would be - /// equivalent to a "single-use region". This is true on - /// impls, but not other kinds of items. - track_lifetime_uses: bool, - - /// Whether or not this binder would serve as the parent - /// binder for opaque types introduced within. For example: - /// - /// ```text - /// fn foo<'a>() -> impl for<'b> Trait> - /// ``` - /// - /// Here, the opaque types we create for the `impl Trait` - /// and `impl Trait2` references will both have the `foo` item - /// as their parent. When we get to `impl Trait2`, we find - /// that it is nested within the `for<>` binder -- this flag - /// allows us to skip that when looking for the parent binder - /// of the resulting opaque type. - opaque_type_parent: bool, - - s: ScopeRef<'a>, - }, - - /// Lifetimes introduced by a fn are scoped to the call-site for that fn, - /// if this is a fn body, otherwise the original definitions are used. - /// Unspecified lifetimes are inferred, unless an elision scope is nested, - /// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. - Body { - id: hir::BodyId, - s: ScopeRef<'a>, - }, - - /// A scope which either determines unspecified lifetimes or errors - /// on them (e.g., due to ambiguity). For more details, see `Elide`. - Elision { - elide: Elide, - s: ScopeRef<'a>, - }, - - /// Use a specific lifetime (if `Some`) or leave it unset (to be - /// inferred in a function body or potentially error outside one), - /// for the default choice of lifetime in a trait object type. - ObjectLifetimeDefault { - lifetime: Option, - s: ScopeRef<'a>, - }, - - Root, -} - -#[derive(Clone, Debug)] -enum Elide { - /// Use a fresh anonymous late-bound lifetime each time, by - /// incrementing the counter to generate sequential indices. - FreshLateAnon(Cell), - /// Always use this one lifetime. - Exact(Region), - /// Less or more than one lifetime were found, error on unspecified. - Error(Vec), -} - -#[derive(Clone, Debug)] -crate struct ElisionFailureInfo { - /// Where we can find the argument pattern. - parent: Option, - /// The index of the argument in the original definition. - index: usize, - lifetime_count: usize, - have_bound_regions: bool, - crate span: Span, -} - -type ScopeRef<'a> = &'a Scope<'a>; - -const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - resolve_lifetimes, - - named_region_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id) - }, - - is_late_bound_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id) - }, - - object_lifetime_defaults_map: |tcx, id| { - let id = LocalDefId::from_def_id(DefId::local(id)); // (*) - tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) - }, - - ..*providers - }; - - // (*) FIXME the query should be defined to take a LocalDefId -} - -/// Computes the `ResolveLifetimes` map that contains data for the -/// entire crate. You should not read the result of this query -/// directly, but rather use `named_region_map`, `is_late_bound_map`, -/// etc. -fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes { - assert_eq!(for_krate, LOCAL_CRATE); - - let named_region_map = krate(tcx); - - let mut rl = ResolveLifetimes::default(); - - for (hir_id, v) in named_region_map.defs { - let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - for hir_id in named_region_map.late_bound { - let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id); - } - for (hir_id, v) in named_region_map.object_lifetime_defaults { - let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default(); - map.insert(hir_id.local_id, v); - } - - tcx.arena.alloc(rl) -} - -fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { - let krate = tcx.hir().krate(); - let mut map = NamedRegionMap { - defs: Default::default(), - late_bound: Default::default(), - object_lifetime_defaults: compute_object_lifetime_defaults(tcx), - }; - { - let mut visitor = LifetimeContext { - tcx, - map: &mut map, - scope: ROOT_SCOPE, - trait_ref_hack: false, - is_in_fn_syntax: false, - labels_in_fn: vec![], - xcrate_object_lifetime_defaults: Default::default(), - lifetime_uses: &mut Default::default(), - missing_named_lifetime_spots: vec![], - }; - for (_, item) in &krate.items { - visitor.visit_item(item); - } - } - map -} - -/// In traits, there is an implicit `Self` type parameter which comes before the generics. -/// We have to account for this when computing the index of the other generic parameters. -/// This function returns whether there is such an implicit parameter defined on the given item. -fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - match *node { - hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => true, - _ => false, - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::All(&self.tcx.hir()) - } - - // We want to nest trait/impl items in their parent, but nothing else. - fn visit_nested_item(&mut self, _: hir::ItemId) {} - - fn visit_nested_body(&mut self, body: hir::BodyId) { - // Each body has their own set of labels, save labels. - let saved = take(&mut self.labels_in_fn); - let body = self.tcx.hir().body(body); - extract_labels(self, body); - self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { - this.visit_body(body); - }); - replace(&mut self.labels_in_fn, saved); - } - - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - match item.kind { - hir::ItemKind::Fn(ref sig, ref generics, _) => { - self.missing_named_lifetime_spots.push(generics.into()); - self.visit_early_late(None, &sig.decl, generics, |this| { - intravisit::walk_item(this, item); - }); - self.missing_named_lifetime_spots.pop(); - } - - hir::ItemKind::ExternCrate(_) - | hir::ItemKind::Use(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod(..) - | hir::ItemKind::GlobalAsm(..) => { - // These sorts of items have no lifetime parameters at all. - intravisit::walk_item(self, item); - } - hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { - // No lifetime parameters, but implied 'static. - let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; - self.with(scope, |_, this| intravisit::walk_item(this, item)); - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => { - // Currently opaque type declarations are just generated from `impl Trait` - // items. Doing anything on this node is irrelevant, as we currently don't need - // it. - } - hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: None, ref generics, .. - }) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::TraitAlias(ref generics, ..) - | hir::ItemKind::Impl { ref generics, .. } => { - self.missing_named_lifetime_spots.push(generics.into()); - - // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". - // This is not true for other kinds of items.x - let track_lifetime_uses = match item.kind { - hir::ItemKind::Impl { .. } => true, - _ => false, - }; - // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.kind) { - 1 // Self comes before lifetimes - } else { - 0 - }; - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - opaque_type_parent: true, - track_lifetime_uses, - s: ROOT_SCOPE, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - intravisit::walk_item(this, item); - }); - self.missing_named_lifetime_spots.pop(); - } - } - } - - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - match item.kind { - hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { - self.visit_early_late(None, decl, generics, |this| { - intravisit::walk_foreign_item(this, item); - }) - } - hir::ForeignItemKind::Static(..) => { - intravisit::walk_foreign_item(self, item); - } - hir::ForeignItemKind::Type => { - intravisit::walk_foreign_item(self, item); - } - } - } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty); - debug!("visit_ty: ty.kind={:?}", ty.kind); - match ty.kind { - hir::TyKind::BareFn(ref c) => { - let next_early_index = self.next_early_index(); - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; - let lifetime_span: Option = c - .generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(param.span), - _ => None, - }) - .last(); - let (span, span_type) = if let Some(span) = lifetime_span { - (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail) - } else { - (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty) - }; - self.missing_named_lifetime_spots - .push(MissingLifetimeSpot::HigherRanked { span, span_type }); - let scope = Scope::Binder { - lifetimes: c - .generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(), - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |old_scope, this| { - // a bare fn has no bounds, so everything - // contained within is scoped within its binder. - this.check_lifetime_params(old_scope, &c.generic_params); - intravisit::walk_ty(this, ty); - }); - self.missing_named_lifetime_spots.pop(); - self.is_in_fn_syntax = was_in_fn_syntax; - } - hir::TyKind::TraitObject(bounds, ref lifetime) => { - debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime); - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } - match lifetime.name { - LifetimeName::Implicit => { - // For types like `dyn Foo`, we should - // generate a special form of elided. - span_bug!(ty.span, "object-lifetime-default expected, not implict",); - } - LifetimeName::ImplicitObjectLifetimeDefault => { - // If the user does not write *anything*, we - // use the object lifetime defaulting - // rules. So e.g., `Box` becomes - // `Box`. - self.resolve_object_lifetime_default(lifetime) - } - LifetimeName::Underscore => { - // If the user writes `'_`, we use the *ordinary* elision - // rules. So the `'_` in e.g., `Box` will be - // resolved the same as the `'_` in `&'_ Foo`. - // - // cc #48468 - self.resolve_elided_lifetimes(vec![lifetime]) - } - LifetimeName::Param(_) | LifetimeName::Static => { - // If the user wrote an explicit name, use that. - self.visit_lifetime(lifetime); - } - LifetimeName::Error => {} - } - } - hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { - self.visit_lifetime(lifetime_ref); - let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), - s: self.scope, - }; - self.with(scope, |_, this| this.visit_ty(&mt.ty)); - } - hir::TyKind::Def(item_id, lifetimes) => { - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `type MyAnonTy<'b> = impl MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the opaque_ty generics - let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { - // Named opaque `impl Trait` types are reached via `TyKind::Path`. - // This arm is for `impl Trait` in the types of statics, constants and locals. - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { - intravisit::walk_ty(self, ty); - return; - } - // RPIT (return position impl trait) - hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, bounds, .. }) => { - (generics, bounds) - } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), - }; - - // Resolve the lifetimes that are applied to the opaque type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - if let hir::GenericArg::Lifetime(lifetime) = lifetime { - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> Trait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id).cloned(); - if let Some(Region::LateBound(_, def_id, _)) = def { - if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir().get_parent_node(hir_id); - let parent_impl_id = hir::ImplItemId { hir_id: parent_id }; - let parent_trait_id = hir::TraitItemId { hir_id: parent_id }; - let krate = self.tcx.hir().krate(); - - if !(krate.items.contains_key(&parent_id) - || krate.impl_items.contains_key(&parent_impl_id) - || krate.trait_items.contains_key(&parent_trait_id)) - { - struct_span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ) - .emit(); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } - } - } - } - } - - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_opaque_type(); - debug!("visit_ty: index = {}", index); - - let mut elision = None; - let mut lifetimes = FxHashMap::default(); - let mut non_lifetime_count = 0; - for param in generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => { - let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m); - let def_id = if let Region::EarlyBound(_, def_id, _) = reg { - def_id - } else { - bug!(); - }; - if let hir::ParamName::Plain(param_name) = name { - if param_name.name == kw::UnderscoreLifetime { - // Pick the elided lifetime "definition" if one exists - // and use it to make an elision scope. - self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); - elision = Some(reg); - } else { - lifetimes.insert(name, reg); - } - } else { - self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many); - lifetimes.insert(name, reg); - } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - } - } - } - let next_early_index = index + non_lifetime_count; - - if let Some(elision_region) = elision { - let scope = - Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; - self.with(scope, |_old_scope, this| { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: this.scope, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - this.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - }); - } else { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - } - } - _ => intravisit::walk_ty(self, ty), - } - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - use self::hir::TraitItemKind::*; - self.missing_named_lifetime_spots.push((&trait_item.generics).into()); - match trait_item.kind { - Method(ref sig, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(trait_item.hir_id)), - &sig.decl, - &trait_item.generics, - |this| intravisit::walk_trait_item(this, trait_item), - ); - } - Type(bounds, ref ty) => { - let generics = &trait_item.generics; - let mut index = self.next_early_index(); - debug!("visit_ty: index = {}", index); - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - if let Some(ty) = ty { - this.visit_ty(ty); - } - }); - } - Const(_, _) => { - // Only methods and types support generics. - assert!(trait_item.generics.params.is_empty()); - intravisit::walk_trait_item(self, trait_item); - } - } - self.missing_named_lifetime_spots.pop(); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - use self::hir::ImplItemKind::*; - self.missing_named_lifetime_spots.push((&impl_item.generics).into()); - match impl_item.kind { - Method(ref sig, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(impl_item.hir_id)), - &sig.decl, - &impl_item.generics, - |this| intravisit::walk_impl_item(this, impl_item), - ) - } - TyAlias(ref ty) => { - let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut non_lifetime_count = 0; - debug!("visit_ty: index = {}", index); - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let scope = Scope::Binder { - lifetimes, - next_early_index: index + non_lifetime_count, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - this.visit_generics(generics); - this.visit_ty(ty); - }); - } - OpaqueTy(bounds) => { - let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut next_early_index = index; - debug!("visit_ty: index = {}", index); - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } => { - next_early_index += 1; - None - } - GenericParamKind::Const { .. } => { - next_early_index += 1; - None - } - }) - .collect(); - - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - } - Const(_, _) => { - // Only methods and types support generics. - assert!(impl_item.generics.params.is_empty()); - intravisit::walk_impl_item(self, impl_item); - } - } - self.missing_named_lifetime_spots.pop(); - } - - fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref); - if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(vec![lifetime_ref]); - return; - } - if lifetime_ref.is_static() { - self.insert_lifetime(lifetime_ref, Region::Static); - return; - } - self.resolve_lifetime_ref(lifetime_ref); - } - - fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { - for (i, segment) in path.segments.iter().enumerate() { - let depth = path.segments.len() - i - 1; - if let Some(ref args) = segment.args { - self.visit_segment_args(path.res, depth, args); - } - } - } - - fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { - let output = match fd.output { - hir::FnRetTy::DefaultReturn(_) => None, - hir::FnRetTy::Return(ref ty) => Some(&**ty), - }; - self.visit_fn_like_elision(&fd.inputs, output); - } - - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); - for param in generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => { - walk_list!(self, visit_param_bound, param.bounds); - if let Some(ref ty) = default { - self.visit_ty(&ty); - } - } - GenericParamKind::Const { ref ty, .. } => { - walk_list!(self, visit_param_bound, param.bounds); - self.visit_ty(&ty); - } - } - } - for predicate in generics.where_clause.predicates { - match predicate { - &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - ref bounded_ty, - bounds, - ref bound_generic_params, - .. - }) => { - let lifetimes: FxHashMap<_, _> = bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(); - if !lifetimes.is_empty() { - self.trait_ref_hack = true; - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - lifetimes, - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - let result = self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &bound_generic_params); - this.visit_ty(&bounded_ty); - walk_list!(this, visit_param_bound, bounds); - }); - self.trait_ref_hack = false; - result - } else { - self.visit_ty(&bounded_ty); - walk_list!(self, visit_param_bound, bounds); - } - } - &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - ref lifetime, - bounds, - .. - }) => { - self.visit_lifetime(lifetime); - walk_list!(self, visit_param_bound, bounds); - } - &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - ref lhs_ty, - ref rhs_ty, - .. - }) => { - self.visit_ty(lhs_ty); - self.visit_ty(rhs_ty); - } - } - } - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'tcx hir::PolyTraitRef<'tcx>, - _modifier: hir::TraitBoundModifier, - ) { - debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - - let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - if !self.trait_ref_hack - || trait_ref.bound_generic_params.iter().any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) - { - if self.trait_ref_hack { - struct_span_err!( - self.tcx.sess, - trait_ref.span, - E0316, - "nested quantification of lifetimes" - ) - .emit(); - } - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - lifetimes: trait_ref - .bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(), - s: self.scope, - next_early_index, - track_lifetime_uses: true, - opaque_type_parent: false, - }; - self.with(scope, |old_scope, this| { - this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); - walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref); - }) - } else { - self.visit_trait_ref(&trait_ref.trait_ref); - } - if should_pop_missing_lt { - self.missing_named_lifetime_spots.pop(); - } - } -} - -#[derive(Copy, Clone, PartialEq)] -enum ShadowKind { - Label, - Lifetime, -} -struct Original { - kind: ShadowKind, - span: Span, -} -struct Shadower { - kind: ShadowKind, - span: Span, -} - -fn original_label(span: Span) -> Original { - Original { kind: ShadowKind::Label, span: span } -} -fn shadower_label(span: Span) -> Shadower { - Shadower { kind: ShadowKind::Label, span: span } -} -fn original_lifetime(span: Span) -> Original { - Original { kind: ShadowKind::Lifetime, span: span } -} -fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower { - Shadower { kind: ShadowKind::Lifetime, span: param.span } -} - -impl ShadowKind { - fn desc(&self) -> &'static str { - match *self { - ShadowKind::Label => "label", - ShadowKind::Lifetime => "lifetime", - } - } -} - -fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) { - let lifetime_params: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), - _ => None, - }) - .collect(); - let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); - let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); - - if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { - struct_span_err!( - tcx.sess, - *in_band_span, - E0688, - "cannot mix in-band and explicit lifetime definitions" - ) - .span_label(*in_band_span, "in-band lifetime definition here") - .span_label(*explicit_span, "explicit lifetime definition here") - .emit(); - } -} - -fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: ast::Name, orig: Original, shadower: Shadower) { - let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { - // lifetime/lifetime shadowing is an error - struct_span_err!( - tcx.sess, - shadower.span, - E0496, - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ) - } else { - // shadowing involving a label is only a warning, due to issues with - // labels and lifetimes not being macro-hygienic. - tcx.sess.struct_span_warn( - shadower.span, - &format!( - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), - name, - orig.kind.desc() - ), - ) - }; - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime {} already in scope", name)); - err.emit(); -} - -// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning -// if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { - struct GatherLabels<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - scope: ScopeRef<'a>, - labels_in_fn: &'a mut Vec, - } - - let mut gather = - GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn }; - gather.visit_body(body); - - impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { - type Map = Map<'v>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &hir::Expr<'_>) { - if let Some(label) = expression_label(ex) { - for prior_label in &self.labels_in_fn[..] { - // FIXME (#24278): non-hygienic comparison - if label.name == prior_label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(prior_label.span), - shadower_label(label.span), - ); - } - } - - check_if_label_shadows_lifetime(self.tcx, self.scope, label); - - self.labels_in_fn.push(label); - } - intravisit::walk_expr(self, ex) - } - } - - fn expression_label(ex: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None } - } - - fn check_if_label_shadows_lifetime( - tcx: TyCtxt<'_>, - mut scope: ScopeRef<'_>, - label: ast::Ident, - ) { - loop { - match *scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - // FIXME (#24278): non-hygienic comparison - if let Some(def) = lifetimes.get(&hir::ParamName::Plain(label.modern())) { - let hir_id = tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); - - signal_shadowing_problem( - tcx, - label.name, - original_lifetime(tcx.hir().span(hir_id)), - shadower_label(label.span), - ); - return; - } - scope = s; - } - } - } - } -} - -fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap> { - let mut map = HirIdMap::default(); - for item in tcx.hir().krate().items.values() { - match item.kind { - hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - ref generics, impl_trait_fn: None, .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); - - // Debugging aid. - if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) { - let object_lifetime_default_reprs: String = result - .iter() - .map(|set| match *set { - Set1::Empty => "BaseDefault".into(), - Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _, _)) => generics - .params - .iter() - .find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if i == 0 { - return Some(param.name.ident().to_string().into()); - } - i -= 1; - None - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - map.insert(item.hir_id, result); - } - _ => {} - } - } - map -} - -/// Scan the bounds and where-clauses on parameters to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` -/// for each type parameter. -fn object_lifetime_defaults_for_item( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, -) -> Vec { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.modern()); - } - } - } - - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; - - add_bounds(&mut set, ¶m.bounds); - - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.where_clause.predicates { - // Look for `type: ...` where clauses. - let data = match *predicate { - hir::WherePredicate::BoundPredicate(ref data) => data, - _ => continue, - }; - - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !data.bound_generic_params.is_empty() { - continue; - } - - let res = match data.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, - _ => continue, - }; - - if res == Res::Def(DefKind::TyParam, param_def_id) { - add_bounds(&mut set, &data.bounds); - } - } - - Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(( - param.hir_id, - hir::LifetimeName::Param(param.name), - LifetimeDefOrigin::from_param(param), - )), - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name, _))| lt_name == name) - .map_or(Set1::Many, |(i, (id, _, origin))| { - let def_id = tcx.hir().local_def_id(id); - Set1::One(Region::EarlyBound(i as u32, def_id, origin)) - }) - } - } - Set1::Many => Set1::Many, - }) - } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - None - } - }) - .collect() -} - -impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - // FIXME(#37666) this works around a limitation in the region inferencer - fn hack(&mut self, f: F) - where - F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), - { - f(self) - } - - fn with(&mut self, wrap_scope: Scope<'_>, f: F) - where - F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), - { - let LifetimeContext { tcx, map, lifetime_uses, .. } = self; - let labels_in_fn = take(&mut self.labels_in_fn); - let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); - let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); - let mut this = LifetimeContext { - tcx: *tcx, - map: map, - scope: &wrap_scope, - trait_ref_hack: self.trait_ref_hack, - is_in_fn_syntax: self.is_in_fn_syntax, - labels_in_fn, - xcrate_object_lifetime_defaults, - lifetime_uses, - missing_named_lifetime_spots, - }; - debug!("entering scope {:?}", this.scope); - f(self.scope, &mut this); - this.check_uses_for_lifetimes_defined_by_scope(); - debug!("exiting scope {:?}", this.scope); - self.labels_in_fn = this.labels_in_fn; - self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; - self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; - } - - /// helper method to determine the span to remove when suggesting the - /// deletion of a lifetime - fn lifetime_deletion_span( - &self, - name: ast::Ident, - generics: &hir::Generics<'_>, - ) -> Option { - generics.params.iter().enumerate().find_map(|(i, param)| { - if param.name.ident() == name { - let mut in_band = false; - if let hir::GenericParamKind::Lifetime { kind } = param.kind { - if let hir::LifetimeParamKind::InBand = kind { - in_band = true; - } - } - if in_band { - Some(param.span) - } else { - if generics.params.len() == 1 { - // if sole lifetime, remove the entire `<>` brackets - Some(generics.span) - } else { - // if removing within `<>` brackets, we also want to - // delete a leading or trailing comma as appropriate - if i >= generics.params.len() - 1 { - Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) - } else { - Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) - } - } - } - } else { - None - } - }) - } - - // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)` - // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` - fn suggest_eliding_single_use_lifetime( - &self, - err: &mut DiagnosticBuilder<'_>, - def_id: DefId, - lifetime: &hir::Lifetime, - ) { - let name = lifetime.name.ident(); - let mut remove_decl = None; - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) { - remove_decl = self.lifetime_deletion_span(name, generics); - } - } - - let mut remove_use = None; - let mut elide_use = None; - let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| { - for input in inputs { - match input.kind { - hir::TyKind::Rptr(lt, _) => { - if lt.name.ident() == name { - // include the trailing whitespace between the lifetime and type names - let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi()); - remove_use = Some( - self.tcx - .sess - .source_map() - .span_until_non_whitespace(lt_through_ty_span), - ); - break; - } - } - hir::TyKind::Path(ref qpath) => { - if let QPath::Resolved(_, path) = qpath { - let last_segment = &path.segments[path.segments.len() - 1]; - let generics = last_segment.generic_args(); - for arg in generics.args.iter() { - if let GenericArg::Lifetime(lt) = arg { - if lt.name.ident() == name { - elide_use = Some(lt.span); - break; - } - } - } - break; - } - } - _ => {} - } - } - }; - if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) { - if let Some(parent) = - self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id)) - { - match parent { - Node::Item(item) => { - if let hir::ItemKind::Fn(sig, _, _) = &item.kind { - find_arg_use_span(sig.decl.inputs); - } - } - Node::ImplItem(impl_item) => { - if let hir::ImplItemKind::Method(sig, _) = &impl_item.kind { - find_arg_use_span(sig.decl.inputs); - } - } - _ => {} - } - } - } - - let msg = "elide the single-use lifetime"; - match (remove_decl, remove_use, elide_use) { - (Some(decl_span), Some(use_span), None) => { - // if both declaration and use deletion spans start at the same - // place ("start at" because the latter includes trailing - // whitespace), then this is an in-band lifetime - if decl_span.shrink_to_lo() == use_span.shrink_to_lo() { - err.span_suggestion( - use_span, - msg, - String::new(), - Applicability::MachineApplicable, - ); - } else { - err.multipart_suggestion( - msg, - vec![(decl_span, String::new()), (use_span, String::new())], - Applicability::MachineApplicable, - ); - } - } - (Some(decl_span), None, Some(use_span)) => { - err.multipart_suggestion( - msg, - vec![(decl_span, String::new()), (use_span, "'_".to_owned())], - Applicability::MachineApplicable, - ); - } - _ => {} - } - } - - fn check_uses_for_lifetimes_defined_by_scope(&mut self) { - let defined_by = match self.scope { - Scope::Binder { lifetimes, .. } => lifetimes, - _ => { - debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); - return; - } - }; - - let mut def_ids: Vec<_> = defined_by - .values() - .flat_map(|region| match region { - Region::EarlyBound(_, def_id, _) - | Region::LateBound(_, def_id, _) - | Region::Free(_, def_id) => Some(*def_id), - - Region::LateBoundAnon(..) | Region::Static => None, - }) - .collect(); - - // ensure that we issue lints in a repeatable order - def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); - - for def_id in def_ids { - debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); - - let lifetimeuseset = self.lifetime_uses.remove(&def_id); - - debug!( - "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", - lifetimeuseset - ); - - match lifetimeuseset { - Some(LifetimeUseSet::One(lifetime)) => { - let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); - debug!("hir id first={:?}", hir_id); - if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { - Node::Lifetime(hir_lifetime) => Some(( - hir_lifetime.hir_id, - hir_lifetime.span, - hir_lifetime.name.ident(), - )), - Node::GenericParam(param) => { - Some((param.hir_id, param.span, param.name.ident())) - } - _ => None, - } { - debug!("id = {:?} span = {:?} name = {:?}", id, span, name); - if name.name == kw::UnderscoreLifetime { - continue; - } - - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(parent_hir_id) = - self.tcx.hir().as_local_hir_id(parent_def_id) - { - // lifetimes in `derive` expansions don't count (Issue #53738) - if self - .tcx - .hir() - .attrs(parent_hir_id) - .iter() - .any(|attr| attr.check_name(sym::automatically_derived)) - { - continue; - } - } - } - - self.tcx.struct_span_lint_hir( - lint::builtin::SINGLE_USE_LIFETIMES, - id, - span, - |lint| { - let mut err = lint.build(&format!( - "lifetime parameter `{}` only used once", - name - )); - if span == lifetime.span { - // spans are the same for in-band lifetime declarations - err.span_label(span, "this lifetime is only used here"); - } else { - err.span_label(span, "this lifetime..."); - err.span_label(lifetime.span, "...is used only here"); - } - self.suggest_eliding_single_use_lifetime( - &mut err, def_id, lifetime, - ); - err.emit(); - }, - ); - } - } - Some(LifetimeUseSet::Many) => { - debug!("not one use lifetime"); - } - None => { - let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); - if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) { - Node::Lifetime(hir_lifetime) => Some(( - hir_lifetime.hir_id, - hir_lifetime.span, - hir_lifetime.name.ident(), - )), - Node::GenericParam(param) => { - Some((param.hir_id, param.span, param.name.ident())) - } - _ => None, - } { - debug!("id ={:?} span = {:?} name = {:?}", id, span, name); - self.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_LIFETIMES, - id, - span, - |lint| { - let mut err = lint - .build(&format!("lifetime parameter `{}` never used", name)); - if let Some(parent_def_id) = self.tcx.parent(def_id) { - if let Some(generics) = - self.tcx.hir().get_generics(parent_def_id) - { - let unused_lt_span = - self.lifetime_deletion_span(name, generics); - if let Some(span) = unused_lt_span { - err.span_suggestion( - span, - "elide the unused lifetime", - String::new(), - Applicability::MachineApplicable, - ); - } - } - } - err.emit(); - }, - ); - } - } - } - } - } - - /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. - /// - /// Handles visiting fns and methods. These are a bit complicated because we must distinguish - /// early- vs late-bound lifetime parameters. We do this by checking which lifetimes appear - /// within type bounds; those are early bound lifetimes, and the rest are late bound. - /// - /// For example: - /// - /// fn foo<'a,'b,'c,T:Trait<'b>>(...) - /// - /// Here `'a` and `'c` are late bound but `'b` is early bound. Note that early- and late-bound - /// lifetimes may be interspersed together. - /// - /// If early bound lifetimes are present, we separate them into their own list (and likewise - /// for late bound). They will be numbered sequentially, starting from the lowest index that is - /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late - /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the - /// ordering is not important there. - fn visit_early_late( - &mut self, - parent_id: Option, - decl: &'tcx hir::FnDecl<'tcx>, - generics: &'tcx hir::Generics<'tcx>, - walk: F, - ) where - F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), - { - insert_late_bound_lifetimes(self.map, decl, generics); - - // Find the start of nested early scopes, e.g., in methods. - let mut index = 0; - if let Some(parent_id) = parent_id { - let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.kind) { - index += 1; // Self comes before lifetimes - } - match parent.kind { - hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::Impl { ref generics, .. } => { - index += generics.params.len() as u32; - } - _ => {} - } - } - - let mut non_lifetime_count = 0; - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.map.late_bound.contains(¶m.hir_id) { - Some(Region::late(&self.tcx.hir(), param)) - } else { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } - }) - .collect(); - let next_early_index = index + non_lifetime_count; - - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - opaque_type_parent: true, - track_lifetime_uses: false, - }; - self.with(scope, move |old_scope, this| { - this.check_lifetime_params(old_scope, &generics.params); - this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` - }); - } - - fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => return 0, - - Scope::Binder { next_early_index, opaque_type_parent, .. } - if (!only_opaque_type_parent || opaque_type_parent) => - { - return next_early_index; - } - - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => scope = s, - } - } - } - - /// Returns the next index one would use for an early-bound-region - /// if extending the current scope. - fn next_early_index(&self) -> u32 { - self.next_early_index_helper(true) - } - - /// Returns the next index one would use for an `impl Trait` that - /// is being converted into an opaque type alias `impl Trait`. This will be the - /// next early index from the enclosing item, for the most - /// part. See the `opaque_type_parent` field for more info. - fn next_early_index_for_opaque_type(&self) -> u32 { - self.next_early_index_helper(false) - } - - fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); - - // If we've already reported an error, just ignore `lifetime_ref`. - if let LifetimeName::Error = lifetime_ref.name { - return; - } - - // Walk up the scope chain, tracking the number of fn scopes - // that we pass through, until we find a lifetime with the - // given name or we run out of scopes. - // search. - let mut late_depth = 0; - let mut scope = self.scope; - let mut outermost_body = None; - let result = loop { - match *scope { - Scope::Body { id, s } => { - outermost_body = Some(id); - scope = s; - } - - Scope::Root => { - break None; - } - - Scope::Binder { ref lifetimes, s, .. } => { - match lifetime_ref.name { - LifetimeName::Param(param_name) => { - if let Some(&def) = lifetimes.get(¶m_name.modern()) { - break Some(def.shifted(late_depth)); - } - } - _ => bug!("expected LifetimeName::Param"), - } - - late_depth += 1; - scope = s; - } - - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - }; - - if let Some(mut def) = result { - if let Region::EarlyBound(..) = def { - // Do not free early-bound regions, only late-bound ones. - } else if let Some(body_id) = outermost_body { - let fn_id = self.tcx.hir().body_owner(body_id); - match self.tcx.hir().get(fn_id) { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(..), - .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Method(..), .. - }) => { - let scope = self.tcx.hir().local_def_id(fn_id); - def = Region::Free(scope, def.id().unwrap()); - } - _ => {} - } - } - - // Check for fn-syntax conflicts with in-band lifetime definitions - if self.is_in_fn_syntax { - match def { - Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) - | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { - struct_span_err!( - self.tcx.sess, - lifetime_ref.span, - E0687, - "lifetimes used in `fn` or `Fn` syntax must be \ - explicitly declared using `<...>` binders" - ) - .span_label(lifetime_ref.span, "in-band lifetime definition") - .emit(); - } - - Region::Static - | Region::EarlyBound(_, _, LifetimeDefOrigin::ExplicitOrElided) - | Region::LateBound(_, _, LifetimeDefOrigin::ExplicitOrElided) - | Region::EarlyBound(_, _, LifetimeDefOrigin::Error) - | Region::LateBound(_, _, LifetimeDefOrigin::Error) - | Region::LateBoundAnon(..) - | Region::Free(..) => {} - } - } - - self.insert_lifetime(lifetime_ref, def); - } else { - self.emit_undeclared_lifetime_error(lifetime_ref); - } - } - - fn visit_segment_args( - &mut self, - res: Res, - depth: usize, - generic_args: &'tcx hir::GenericArgs<'tcx>, - ) { - debug!( - "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", - res, depth, generic_args, - ); - - if generic_args.parenthesized { - let was_in_fn_syntax = self.is_in_fn_syntax; - self.is_in_fn_syntax = true; - self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); - self.is_in_fn_syntax = was_in_fn_syntax; - return; - } - - let mut elide_lifetimes = true; - let lifetimes = generic_args - .args - .iter() - .filter_map(|arg| match arg { - hir::GenericArg::Lifetime(lt) => { - if !lt.is_elided() { - elide_lifetimes = false; - } - Some(lt) - } - _ => None, - }) - .collect(); - if elide_lifetimes { - self.resolve_elided_lifetimes(lifetimes); - } else { - lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); - } - - // Figure out if this is a type/trait segment, - // which requires object lifetime defaults. - let parent_def_id = |this: &mut Self, def_id: DefId| { - let def_key = this.tcx.def_key(def_id); - DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } - }; - let type_def_id = match res { - Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Struct, def_id) - | Res::Def(DefKind::Union, def_id) - | Res::Def(DefKind::Enum, def_id) - | Res::Def(DefKind::TyAlias, def_id) - | Res::Def(DefKind::Trait, def_id) - if depth == 0 => - { - Some(def_id) - } - _ => None, - }; - - debug!("visit_segment_args: type_def_id={:?}", type_def_id); - - // Compute a vector of defaults, one for each type parameter, - // per the rules given in RFCs 599 and 1156. Example: - // - // ```rust - // struct Foo<'a, T: 'a, U> { } - // ``` - // - // If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default - // `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound) - // and `dyn Baz` to `dyn Baz + 'static` (because there is no - // such bound). - // - // Therefore, we would compute `object_lifetime_defaults` to a - // vector like `['x, 'static]`. Note that the vector only - // includes type parameters. - let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { - let in_body = { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => break false, - - Scope::Body { .. } => break true, - - Scope::Binder { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - } - }; - - let map = &self.map; - let unsubst = if let Some(id) = self.tcx.hir().as_local_hir_id(def_id) { - &map.object_lifetime_defaults[&id] - } else { - let tcx = self.tcx; - self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { - tcx.generics_of(def_id) - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, - }) - .collect() - }) - }; - debug!("visit_segment_args: unsubst={:?}", unsubst); - unsubst - .iter() - .map(|set| match *set { - Set1::Empty => { - if in_body { - None - } else { - Some(Region::Static) - } - } - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }); - r.subst(lifetimes, map) - } - Set1::Many => None, - }) - .collect() - }); - - debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); - - let mut i = 0; - for arg in generic_args.args { - match arg { - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => { - if let Some(<) = object_lifetime_defaults.get(i) { - let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(ty)); - } else { - self.visit_ty(ty); - } - i += 1; - } - GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); - } - } - } - - // Hack: when resolving the type `XX` in binding like `dyn - // Foo<'b, Item = XX>`, the current object-lifetime default - // would be to examine the trait `Foo` to check whether it has - // a lifetime bound declared on `Item`. e.g., if `Foo` is - // declared like so, then the default object lifetime bound in - // `XX` should be `'b`: - // - // ```rust - // trait Foo<'a> { - // type Item: 'a; - // } - // ``` - // - // but if we just have `type Item;`, then it would be - // `'static`. However, we don't get all of this logic correct. - // - // Instead, we do something hacky: if there are no lifetime parameters - // to the trait, then we simply use a default object lifetime - // bound of `'static`, because there is no other possibility. On the other hand, - // if there ARE lifetime parameters, then we require the user to give an - // explicit bound for now. - // - // This is intended to leave room for us to implement the - // correct behavior in the future. - let has_lifetime_parameter = generic_args.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }); - - // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. - for b in generic_args.bindings { - let scope = Scope::ObjectLifetimeDefault { - lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, - s: self.scope, - }; - self.with(scope, |_, this| this.visit_assoc_type_binding(b)); - } - } - - fn visit_fn_like_elision( - &mut self, - inputs: &'tcx [hir::Ty<'tcx>], - output: Option<&'tcx hir::Ty<'tcx>>, - ) { - debug!("visit_fn_like_elision: enter"); - let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); - let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope }; - self.with(arg_scope, |_, this| { - for input in inputs { - this.visit_ty(input); - } - match *this.scope { - Scope::Elision { ref elide, .. } => { - arg_elide = elide.clone(); - } - _ => bug!(), - } - }); - - let output = match output { - Some(ty) => ty, - None => return, - }; - - debug!("visit_fn_like_elision: determine output"); - - // Figure out if there's a body we can get argument names from, - // and whether there's a `self` argument (treated specially). - let mut assoc_item_kind = None; - let mut impl_self = None; - let parent = self.tcx.hir().get_parent_node(output.hir_id); - let body = match self.tcx.hir().get(parent) { - // `fn` definitions and methods. - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body), - - Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(_, ref m), .. - }) => { - if let hir::ItemKind::Trait(.., ref trait_items) = - self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind - { - assoc_item_kind = - trait_items.iter().find(|ti| ti.id.hir_id == parent).map(|ti| ti.kind); - } - match *m { - hir::TraitMethod::Required(_) => None, - hir::TraitMethod::Provided(body) => Some(body), - } - } - - Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Method(_, body), .. }) => { - if let hir::ItemKind::Impl { ref self_ty, ref items, .. } = - self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind - { - impl_self = Some(self_ty); - assoc_item_kind = - items.iter().find(|ii| ii.id.hir_id == parent).map(|ii| ii.kind); - } - Some(body) - } - - // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). - Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, - // Everything else (only closures?) doesn't - // actually enjoy elision in return types. - _ => { - self.visit_ty(output); - return; - } - }; - - let has_self = match assoc_item_kind { - Some(hir::AssocItemKind::Method { has_self }) => has_self, - _ => false, - }; - - // In accordance with the rules for lifetime elision, we can determine - // what region to use for elision in the output type in two ways. - // First (determined here), if `self` is by-reference, then the - // implied output region is the region of the self parameter. - if has_self { - struct SelfVisitor<'a> { - map: &'a NamedRegionMap, - impl_self: Option<&'a hir::TyKind<'a>>, - lifetime: Set1, - } - - impl SelfVisitor<'_> { - // Look for `self: &'a Self` - also desugared from `&'a self`, - // and if that matches, use it for elision and return early. - fn is_self_ty(&self, res: Res) -> bool { - if let Res::SelfTy(..) = res { - return true; - } - - // Can't always rely on literal (or implied) `Self` due - // to the way elision rules were originally specified. - if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = - self.impl_self - { - match path.res { - // Whitelist the types that unambiguously always - // result in the same type constructor being used - // (it can't differ between `Self` and `self`). - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Enum, _) - | Res::PrimTy(_) => return res == path.res, - _ => {} - } - } - - false - } - } - - impl<'a> Visitor<'a> for SelfVisitor<'a> { - type Map = Map<'a>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) { - if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind - { - if self.is_self_ty(path.res) { - if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { - self.lifetime.insert(*lifetime); - } - } - } - } - intravisit::walk_ty(self, ty) - } - } - - let mut visitor = SelfVisitor { - map: self.map, - impl_self: impl_self.map(|ty| &ty.kind), - lifetime: Set1::Empty, - }; - visitor.visit_ty(&inputs[0]); - if let Set1::One(lifetime) = visitor.lifetime { - let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); - return; - } - } - - // Second, if there was exactly one lifetime (either a substitution or a - // reference) in the arguments, then any anonymous regions in the output - // have that lifetime. - let mut possible_implied_output_region = None; - let mut lifetime_count = 0; - let arg_lifetimes = inputs - .iter() - .enumerate() - .skip(has_self as usize) - .map(|(i, input)| { - let mut gather = GatherLifetimes { - map: self.map, - outer_index: ty::INNERMOST, - have_bound_regions: false, - lifetimes: Default::default(), - }; - gather.visit_ty(input); - - lifetime_count += gather.lifetimes.len(); - - if lifetime_count == 1 && gather.lifetimes.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = gather.lifetimes.iter().cloned().next(); - } - - ElisionFailureInfo { - parent: body, - index: i, - lifetime_count: gather.lifetimes.len(), - have_bound_regions: gather.have_bound_regions, - span: input.span, - } - }) - .collect(); - - let elide = if lifetime_count == 1 { - Elide::Exact(possible_implied_output_region.unwrap()) - } else { - Elide::Error(arg_lifetimes) - }; - - debug!("visit_fn_like_elision: elide={:?}", elide); - - let scope = Scope::Elision { elide, s: self.scope }; - self.with(scope, |_, this| this.visit_ty(output)); - debug!("visit_fn_like_elision: exit"); - - struct GatherLifetimes<'a> { - map: &'a NamedRegionMap, - outer_index: ty::DebruijnIndex, - have_bound_regions: bool, - lifetimes: FxHashSet, - } - - impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { - type Map = Map<'v>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - if let hir::TyKind::BareFn(_) = ty.kind { - self.outer_index.shift_in(1); - } - match ty.kind { - hir::TyKind::TraitObject(bounds, ref lifetime) => { - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } - - // Stay on the safe side and don't include the object - // lifetime default (which may not end up being used). - if !lifetime.is_elided() { - self.visit_lifetime(lifetime); - } - } - _ => { - intravisit::walk_ty(self, ty); - } - } - if let hir::TyKind::BareFn(_) = ty.kind { - self.outer_index.shift_out(1); - } - } - - fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) { - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - // FIXME(eddyb) Do we want this? It only makes a difference - // if this `for<'a>` lifetime parameter is never used. - self.have_bound_regions = true; - } - - intravisit::walk_generic_param(self, param); - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &hir::PolyTraitRef<'_>, - modifier: hir::TraitBoundModifier, - ) { - self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.outer_index.shift_out(1); - } - - fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { - if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { - match lifetime { - Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) - if debruijn < self.outer_index => - { - self.have_bound_regions = true; - } - _ => { - self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index)); - } - } - } - } - } - } - - fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { - debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); - - if lifetime_refs.is_empty() { - return; - } - - let span = lifetime_refs[0].span; - let mut late_depth = 0; - let mut scope = self.scope; - let mut lifetime_names = FxHashSet::default(); - let error = loop { - match *scope { - // Do not assign any resolution, it will be inferred. - Scope::Body { .. } => return, - - Scope::Root => break None, - - Scope::Binder { s, ref lifetimes, .. } => { - // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); - } - } - late_depth += 1; - scope = s; - } - - Scope::Elision { ref elide, ref s, .. } => { - let lifetime = match *elide { - Elide::FreshLateAnon(ref counter) => { - for lifetime_ref in lifetime_refs { - let lifetime = Region::late_anon(counter).shifted(late_depth); - self.insert_lifetime(lifetime_ref, lifetime); - } - return; - } - Elide::Exact(l) => l.shifted(late_depth), - Elide::Error(ref e) => { - if let Scope::Binder { ref lifetimes, .. } = s { - // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); - } - } - } - break Some(e); - } - }; - for lifetime_ref in lifetime_refs { - self.insert_lifetime(lifetime_ref, lifetime); - } - return; - } - - Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - } - }; - - let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); - let mut add_label = true; - - if let Some(params) = error { - if lifetime_refs.len() == 1 { - add_label = add_label && self.report_elision_failure(&mut err, params, span); - } - } - if add_label { - self.add_missing_lifetime_specifiers_label( - &mut err, - span, - lifetime_refs.len(), - &lifetime_names, - error.map(|p| &p[..]).unwrap_or(&[]), - ); - } - - err.emit(); - } - - fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { - match self.tcx.sess.source_map().span_to_snippet(span) { - Ok(ref snippet) => { - let (sugg, applicability) = if snippet == "&" { - ("&'static ".to_owned(), Applicability::MachineApplicable) - } else if snippet == "'_" { - ("'static".to_owned(), Applicability::MachineApplicable) - } else { - (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) - }; - db.span_suggestion(span, msg, sugg, applicability); - false - } - Err(_) => { - db.help(msg); - true - } - } - } - - fn report_elision_failure( - &mut self, - db: &mut DiagnosticBuilder<'_>, - params: &[ElisionFailureInfo], - span: Span, - ) -> bool { - let mut m = String::new(); - let len = params.len(); - - let elided_params: Vec<_> = - params.iter().cloned().filter(|info| info.lifetime_count > 0).collect(); - - let elided_len = elided_params.len(); - - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } = - info; - - db.span_label(span, ""); - let help_name = if let Some(ident) = - parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident()) - { - format!("`{}`", ident) - } else { - format!("argument {}", index + 1) - }; - - m.push_str( - &(if n == 1 { - help_name - } else { - format!( - "one of {}'s {} {}lifetimes", - help_name, - n, - if have_bound_regions { "free " } else { "" } - ) - })[..], - ); - - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); - } - } - - if len == 0 { - db.help( - "this function's return type contains a borrowed value, \ - but there is no value for it to be borrowed from", - ); - self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") - } else if elided_len == 0 { - db.help( - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments", - ); - let msg = "consider giving it an explicit bounded or 'static lifetime"; - self.suggest_lifetime(db, span, msg) - } else if elided_len == 1 { - db.help(&format!( - "this function's return type contains a borrowed value, \ - but the signature does not say which {} it is borrowed from", - m - )); - true - } else { - db.help(&format!( - "this function's return type contains a borrowed value, \ - but the signature does not say whether it is borrowed from {}", - m - )); - true - } - } - - fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { - debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); - let mut late_depth = 0; - let mut scope = self.scope; - let lifetime = loop { - match *scope { - Scope::Binder { s, .. } => { - late_depth += 1; - scope = s; - } - - Scope::Root | Scope::Elision { .. } => break Region::Static, - - Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, - } - }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); - } - - fn check_lifetime_params( - &mut self, - old_scope: ScopeRef<'_>, - params: &'tcx [hir::GenericParam<'tcx>], - ) { - let lifetimes: Vec<_> = params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), - _ => None, - }) - .collect(); - for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { - if let hir::ParamName::Plain(_) = lifetime_i_name { - let name = lifetime_i_name.ident().name; - if name == kw::UnderscoreLifetime || name == kw::StaticLifetime { - let mut err = struct_span_err!( - self.tcx.sess, - lifetime_i.span, - E0262, - "invalid lifetime parameter name: `{}`", - lifetime_i.name.ident(), - ); - err.span_label( - lifetime_i.span, - format!("{} is a reserved lifetime name", name), - ); - err.emit(); - } - } - - // It is a hard error to shadow a lifetime within the same scope. - for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { - if lifetime_i_name == lifetime_j_name { - struct_span_err!( - self.tcx.sess, - lifetime_j.span, - E0263, - "lifetime name `{}` declared twice in the same scope", - lifetime_j.name.ident() - ) - .span_label(lifetime_j.span, "declared twice") - .span_label(lifetime_i.span, "previous declaration here") - .emit(); - } - } - - // It is a soft error to shadow a lifetime within a parent scope. - self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); - - for bound in lifetime_i.bounds { - match bound { - hir::GenericBound::Outlives(ref lt) => match lt.name { - hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( - lt.span, - "use of `'_` in illegal place, but not caught by lowering", - ), - hir::LifetimeName::Static => { - self.insert_lifetime(lt, Region::Static); - self.tcx - .sess - .struct_span_warn( - lifetime_i.span.to(lt.span), - &format!( - "unnecessary lifetime parameter `{}`", - lifetime_i.name.ident(), - ), - ) - .help(&format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime_i.name.ident(), - )) - .emit(); - } - hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { - self.resolve_lifetime_ref(lt); - } - hir::LifetimeName::ImplicitObjectLifetimeDefault => { - self.tcx.sess.delay_span_bug( - lt.span, - "lowering generated `ImplicitObjectLifetimeDefault` \ - outside of an object type", - ) - } - hir::LifetimeName::Error => { - // No need to do anything, error already reported. - } - }, - _ => bug!(), - } - } - } - } - - fn check_lifetime_param_for_shadowing( - &self, - mut old_scope: ScopeRef<'_>, - param: &'tcx hir::GenericParam<'tcx>, - ) { - for label in &self.labels_in_fn { - // FIXME (#24278): non-hygienic comparison - if param.name.ident().name == label.name { - signal_shadowing_problem( - self.tcx, - label.name, - original_label(label.span), - shadower_lifetime(¶m), - ); - return; - } - } - - loop { - match *old_scope { - Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { - old_scope = s; - } - - Scope::Root => { - return; - } - - Scope::Binder { ref lifetimes, s, .. } => { - if let Some(&def) = lifetimes.get(¶m.name.modern()) { - let hir_id = self.tcx.hir().as_local_hir_id(def.id().unwrap()).unwrap(); - - signal_shadowing_problem( - self.tcx, - param.name.ident().name, - original_lifetime(self.tcx.hir().span(hir_id)), - shadower_lifetime(¶m), - ); - return; - } - - old_scope = s; - } - } - } - } - - /// Returns `true` if, in the current scope, replacing `'_` would be - /// equivalent to a single-use lifetime. - fn track_lifetime_uses(&self) -> bool { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => break false, - - // Inside of items, it depends on the kind of item. - Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses, - - // Inside a body, `'_` will use an inference variable, - // should be fine. - Scope::Body { .. } => break true, - - // A lifetime only used in a fn argument could as well - // be replaced with `'_`, as that would generate a - // fresh name, too. - Scope::Elision { elide: Elide::FreshLateAnon(_), .. } => break true, - - // In the return type or other such place, `'_` is not - // going to make a fresh name, so we cannot - // necessarily replace a single-use lifetime with - // `'_`. - Scope::Elision { elide: Elide::Exact(_), .. } => break false, - Scope::Elision { elide: Elide::Error(_), .. } => break false, - - Scope::ObjectLifetimeDefault { s, .. } => scope = s, - } - } - } - - fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { - if lifetime_ref.hir_id == hir::DUMMY_HIR_ID { - span_bug!( - lifetime_ref.span, - "lifetime reference not renumbered, \ - probably a bug in syntax::fold" - ); - } - - debug!( - "insert_lifetime: {} resolved to {:?} span={:?}", - self.tcx.hir().node_to_string(lifetime_ref.hir_id), - def, - self.tcx.sess.source_map().span_to_string(lifetime_ref.span) - ); - self.map.defs.insert(lifetime_ref.hir_id, def); - - match def { - Region::LateBoundAnon(..) | Region::Static => { - // These are anonymous lifetimes or lifetimes that are not declared. - } - - Region::Free(_, def_id) - | Region::LateBound(_, def_id, _) - | Region::EarlyBound(_, def_id, _) => { - // A lifetime declared by the user. - let track_lifetime_uses = self.track_lifetime_uses(); - debug!("insert_lifetime: track_lifetime_uses={}", track_lifetime_uses); - if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { - debug!("insert_lifetime: first use of {:?}", def_id); - self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref)); - } else { - debug!("insert_lifetime: many uses of {:?}", def_id); - self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); - } - } - } - } - - /// Sometimes we resolve a lifetime, but later find that it is an - /// error (esp. around impl trait). In that case, we remove the - /// entry into `map.defs` so as not to confuse later code. - fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { - let old_value = self.map.defs.remove(&lifetime_ref.hir_id); - assert_eq!(old_value, Some(bad_def)); - } -} - -/// Detects late-bound lifetimes and inserts them into -/// `map.late_bound`. -/// -/// A region declared on a fn is **late-bound** if: -/// - it is constrained by an argument type; -/// - it does not appear in a where-clause. -/// -/// "Constrained" basically means that it appears in any type but -/// not amongst the inputs to a projection. In other words, `<&'a -/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -fn insert_late_bound_lifetimes( - map: &mut NamedRegionMap, - decl: &hir::FnDecl<'_>, - generics: &hir::Generics<'_>, -) { - debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); - - let mut constrained_by_input = ConstrainedCollector::default(); - for arg_ty in decl.inputs { - constrained_by_input.visit_ty(arg_ty); - } - - let mut appears_in_output = AllCollector::default(); - intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); - - debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", constrained_by_input.regions); - - // Walk the lifetimes that appear in where clauses. - // - // Subtle point: because we disallow nested bindings, we can just - // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector::default(); - appears_in_where_clause.visit_generics(generics); - - for param in generics.params { - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - if !param.bounds.is_empty() { - // `'a: 'b` means both `'a` and `'b` are referenced - appears_in_where_clause - .regions - .insert(hir::LifetimeName::Param(param.name.modern())); - } - } - } - - debug!( - "insert_late_bound_lifetimes: appears_in_where_clause={:?}", - appears_in_where_clause.regions - ); - - // Late bound regions are those that: - // - appear in the inputs - // - do not appear in the where-clauses - // - are not implicitly captured by `impl Trait` - for param in generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { /* fall through */ } - - // Neither types nor consts are late-bound. - hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, - } - - let lt_name = hir::LifetimeName::Param(param.name.modern()); - // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(<_name) { - continue; - } - - // does not appear in the inputs, but appears in the return type? early-bound. - if !constrained_by_input.regions.contains(<_name) - && appears_in_output.regions.contains(<_name) - { - continue; - } - - debug!( - "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", - param.name.ident(), - param.hir_id - ); - - let inserted = map.late_bound.insert(param.hir_id); - assert!(inserted, "visited lifetime {:?} twice", param.hir_id); - } - - return; - - #[derive(Default)] - struct ConstrainedCollector { - regions: FxHashSet, - } - - impl<'v> Visitor<'v> for ConstrainedCollector { - type Map = Map<'v>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::None - } - - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) - | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { - // ignore lifetimes appearing in associated type - // projections, as they are not *constrained* - // (defined above) - } - - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { - // consider only the lifetimes on the final - // segment; I am not sure it's even currently - // valid to have them elsewhere, but even if it - // is, those would be potentially inputs to - // projections - if let Some(last_segment) = path.segments.last() { - self.visit_path_segment(path.span, last_segment); - } - } - - _ => { - intravisit::walk_ty(self, ty); - } - } - } - - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.modern()); - } - } - - #[derive(Default)] - struct AllCollector { - regions: FxHashSet, - } - - impl<'v> Visitor<'v> for AllCollector { - type Map = Map<'v>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::None - } - - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name.modern()); - } - } -} -- cgit 1.4.1-3-g733a5 From 6a1790524a820f92652fb3dc5ffc20287a69e5e0 Mon Sep 17 00:00:00 2001 From: YI Date: Wed, 26 Feb 2020 08:56:55 +0800 Subject: update llvm to silence gcc 9 warnings Closes https://github.com/rust-lang/rust/issues/69078 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 73cf98d8656..9f65ad05735 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 73cf98d8656736781e3ea667011d2aefc21f521e +Subproject commit 9f65ad057357b307180955831968f79e74090a90 -- cgit 1.4.1-3-g733a5 From 1a6b930eebe39aa11d948815b9cd9b792a6de8b4 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Wed, 26 Feb 2020 12:43:37 +0100 Subject: clarify operator precedence --- src/libcore/hash/sip.rs | 2 +- src/librustc/ty/query/on_disk_cache.rs | 2 +- src/librustc_data_structures/sip128.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index c4fbd9dbada..aa50e7cdf57 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -304,7 +304,7 @@ impl super::Hasher for Hasher { if self.ntail != 0 { needed = 8 - self.ntail; - self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); if length < needed { self.ntail += length; return; diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 0fb5f66feca..f96bf6c110c 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -997,7 +997,7 @@ impl SpecializedEncoder for opaque::Encoder { fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { let start_pos = self.position(); for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { - ((x.0 >> i * 8) as u8).encode(self)?; + ((x.0 >> (i * 8)) as u8).encode(self)?; } let end_pos = self.position(); assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); diff --git a/src/librustc_data_structures/sip128.rs b/src/librustc_data_structures/sip128.rs index af0e9f79fe1..beb28dd0720 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/src/librustc_data_structures/sip128.rs @@ -274,7 +274,7 @@ impl Hasher for SipHasher128 { if self.ntail != 0 { needed = 8 - self.ntail; - self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); if length < needed { self.ntail += length; return; -- cgit 1.4.1-3-g733a5 From 129ac011b538e09a4538bd5213e74c56f81067e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 26 Feb 2020 12:56:30 +0100 Subject: Clean up E0373 explanation --- src/librustc_error_codes/error_codes/E0373.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0373.md b/src/librustc_error_codes/error_codes/E0373.md index 808363e6eb0..fd969877931 100644 --- a/src/librustc_error_codes/error_codes/E0373.md +++ b/src/librustc_error_codes/error_codes/E0373.md @@ -1,6 +1,6 @@ -This error occurs when an attempt is made to use data captured by a closure, -when that data may no longer exist. It's most commonly seen when attempting to -return a closure: +A captured variable in a closure may not live long enough. + +Erroneous code example: ```compile_fail,E0373 fn foo() -> Box u32> { @@ -9,6 +9,10 @@ fn foo() -> Box u32> { } ``` +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure as shown in the previous code example. + Notice that `x` is stack-allocated by `foo()`. By default, Rust captures closed-over data by reference. This means that once `foo()` returns, `x` no longer exists. An attempt to access `x` within the closure would thus be -- cgit 1.4.1-3-g733a5 From 3d47ebeb0e96e328f247cb691f376e6431f258aa Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 26 Feb 2020 15:08:21 -0800 Subject: Simplify the signature of par_for_each_in Given `T: IntoIterator`/`IntoParallelIterator`, `T::Item` is unambiguous, so we don't need the explicit trait casting. --- src/librustc_data_structures/sync.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index fa98b4d72dd..9051b1751b1 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -203,11 +203,7 @@ cfg_if! { t.into_iter() } - pub fn par_for_each_in( - t: T, - for_each: - impl Fn(<::IntoIter as Iterator>::Item) + Sync + Send - ) { + pub fn par_for_each_in(t: T, for_each: impl Fn(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -397,9 +393,7 @@ cfg_if! { pub fn par_for_each_in( t: T, - for_each: impl Fn( - <::Iter as ParallelIterator>::Item - ) + Sync + Send + for_each: impl Fn(T::Item) + Sync + Send, ) { t.into_par_iter().for_each(for_each) } -- cgit 1.4.1-3-g733a5 From 2c7c4460bba37ff077e9d56c9dff5b67ecdef8e2 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 26 Feb 2020 20:54:13 -0500 Subject: Enable setting diagnostic labels --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 7ece7f977ce..a174dd1e7f3 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,6 +1,7 @@ [relabel] allow-unauthenticated = [ "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", + "D-*", "requires-nightly", # I-* without I-nominated "I-*", "!I-nominated", -- cgit 1.4.1-3-g733a5