From 1d08b1b0421cc287218196e5fdd144b3e82a482a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 18 Jun 2020 13:10:22 +0200 Subject: [PATCH 01/30] Clean up E0689 explanation --- src/librustc_error_codes/error_codes/E0689.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0689.md b/src/librustc_error_codes/error_codes/E0689.md index 26c2c15ccfaac..a680a20421127 100644 --- a/src/librustc_error_codes/error_codes/E0689.md +++ b/src/librustc_error_codes/error_codes/E0689.md @@ -1,13 +1,16 @@ -This error indicates that the numeric value for the method being passed exists -but the type of the numeric value or binding could not be identified. +A method was called on an ambiguous numeric type. -The error happens on numeric literals: +Erroneous code example: ```compile_fail,E0689 -2.0.neg(); +2.0.neg(); // error! ``` -and on numeric bindings without an identified concrete type: +This error indicates that the numeric value for the method being passed exists +but the type of the numeric value or binding could not be identified. + +The error happens on numeric literals and on numeric bindings without an +identified concrete type: ```compile_fail,E0689 let x = 2.0; @@ -19,8 +22,8 @@ Because of this, you must give the numeric literal or binding a type: ``` use std::ops::Neg; -let _ = 2.0_f32.neg(); +let _ = 2.0_f32.neg(); // ok! let x: f32 = 2.0; -let _ = x.neg(); -let _ = (2.0 as f32).neg(); +let _ = x.neg(); // ok! +let _ = (2.0 as f32).neg(); // ok! ``` From 9245ba83047b14fc7c9cef4c7d2bf37828c445b6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 12 Jun 2020 19:25:14 +0200 Subject: [PATCH 02/30] Remove the const_raw_ptr_comparison feature gate. We can never supply a meaningful implementation of this. Instead, the follow up commits will create two intrinsics that approximate comparisons: * `ptr_maybe_eq` * `ptr_maybe_ne` The fact that `ptr_maybe_eq(a, b)` is not necessarily the same value as `!ptr_maybe_ne(a, b)` is a symptom of this entire problem. --- src/librustc_feature/active.rs | 3 -- src/librustc_feature/removed.rs | 5 ++ .../transform/check_consts/ops.rs | 26 +++++++---- src/librustc_mir/transform/check_unsafety.rs | 15 ------ src/librustc_typeck/collect/type_of.rs | 26 +++++------ .../ui/const-generics/fn-const-param-call.rs | 7 ++- .../const-generics/fn-const-param-call.stderr | 18 ++++++-- .../ui/const-generics/fn-const-param-infer.rs | 11 +++-- .../fn-const-param-infer.stderr | 41 +++-------------- .../raw-ptr-const-param-deref.rs | 7 ++- .../raw-ptr-const-param-deref.stderr | 18 ++++++-- .../ui/const-generics/raw-ptr-const-param.rs | 6 +-- .../const-generics/raw-ptr-const-param.stderr | 14 ++---- .../ui/consts/const-eval/const_raw_ptr_ops.rs | 15 +----- .../const-eval/const_raw_ptr_ops.stderr | 46 +++++-------------- .../consts/const-eval/const_raw_ptr_ops2.rs | 13 ++++++ .../const-eval/const_raw_ptr_ops2.stderr | 28 +++++++++++ .../consts/const-eval/promoted_raw_ptr_ops.rs | 2 +- .../ui/consts/miri_unleashed/ptr_arith.stderr | 2 +- src/test/ui/error-codes/E0395.rs | 4 +- src/test/ui/error-codes/E0395.stderr | 9 ++-- .../feature-gate-const_generics-ptr.rs | 4 +- .../feature-gate-const_generics-ptr.stderr | 10 +--- src/test/ui/issues/issue-25826.rs | 2 +- src/test/ui/issues/issue-25826.stderr | 7 ++- .../ui/unsafe/unsafe-unstable-const-fn.rs | 8 ++-- .../ui/unsafe/unsafe-unstable-const-fn.stderr | 8 ++-- 27 files changed, 165 insertions(+), 190 deletions(-) create mode 100644 src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs create mode 100644 src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index d186f35a12b5a..f167ed97f57e2 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -401,9 +401,6 @@ declare_features! ( /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - /// Allows comparing raw pointers during const eval. - (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - /// Allows `#[doc(alias = "...")]`. (active, doc_alias, "1.27.0", Some(50146), None), diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs index 4e348054fbd4b..8d410894e8b19 100644 --- a/src/librustc_feature/removed.rs +++ b/src/librustc_feature/removed.rs @@ -113,6 +113,11 @@ declare_features! ( Some("removed in favor of `#![feature(marker_trait_attr)]`")), /// Allows `#[no_debug]`. (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), + + /// Allows comparing raw pointers during const eval. + (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, + Some("cannot be allowed in const eval in any meaningful way")), + // ------------------------------------------------------------------------- // feature-group-end: removed features // ------------------------------------------------------------------------- diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index d5059c98c9511..f09b598ce069d 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -284,18 +284,24 @@ impl NonConstOp for Panic { #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { - fn feature_gate() -> Option { - Some(sym::const_compare_raw_pointers) - } - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_compare_raw_pointers, + let mut err = ccx.tcx.sess.struct_span_err( span, - &format!("comparing raw pointers inside {}", ccx.const_kind()), - ) - .emit(); + "pointers cannot be compared in a meaningful way during const eval.", + ); + err.note( + "It is conceptually impossible for const eval to know in all cases whether two \ + pointers are equal. While sometimes it is clear (the address of a static item \ + is never equal to the address of another static item), comparing an integer \ + address with any allocation's address is impossible to do at compile-time.", + ); + err.note( + "That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all \ + comparisons where CTFE isn't sure whether two addresses are equal. The mirror \ + intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't \ + sure whether two addresses are inequal.", + ); + err.emit(); } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 7dbb2ebad8b99..ac7acff1eca9e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -171,21 +171,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { _ => {} } } - // raw pointer and fn pointer operations are unsafe as it is not clear whether one - // pointer would be "less" or "equal" to another, because we cannot know where llvm - // or the linker will place various statics in memory. Without this information the - // result of a comparison of addresses would differ between runtime and compile-time. - Rvalue::BinaryOp(_, ref lhs, _) - if self.const_context && self.tcx.features().const_compare_raw_pointers => - { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { - self.require_unsafe( - "pointer operation", - "operations on pointers in constants", - UnsafetyViolationKind::General, - ); - } - } _ => {} } self.super_rvalue(rvalue, location); diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index cf5f2ec69d8d8..3dd9c9c5c39db 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -10,8 +10,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; -use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits; @@ -303,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), GenericParamKind::Const { ty: ref hir_ty, .. } => { let ty = icx.to_ty(hir_ty); - if !tcx.features().const_compare_raw_pointers { - let err = match ty.peel_refs().kind { - ty::FnPtr(_) => Some("function pointers"), - ty::RawPtr(_) => Some("raw pointers"), - _ => None, - }; - if let Some(unsupported_type) = err { - feature_err( - &tcx.sess.parse_sess, - sym::const_compare_raw_pointers, + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + tcx.sess + .struct_span_err( hir_ty.span, &format!( - "using {} as const generic parameters is unstable", + "using {} as const generic parameters is forbidden", unsupported_type ), ) .emit(); - }; - } + }; if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) .is_some() { diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs index afa577fa67ff2..90c438b05cb81 100644 --- a/src/test/ui/const-generics/fn-const-param-call.rs +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -1,15 +1,14 @@ -// run-pass - -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete fn function() -> u32 { 17 } -struct Wrapper u32>; +struct Wrapper u32>; //~ ERROR: using function pointers as const generic parameters impl u32> Wrapper { +//~^ ERROR: using function pointers as const generic parameters fn call() -> u32 { F() } diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr index 9c0f7e3ab9b87..b5811243caa8a 100644 --- a/src/test/ui/const-generics/fn-const-param-call.stderr +++ b/src/test/ui/const-generics/fn-const-param-call.stderr @@ -1,11 +1,23 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/fn-const-param-call.rs:3:12 + --> $DIR/fn-const-param-call.rs:1:12 | -LL | #![feature(const_generics, const_compare_raw_pointers)] +LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:8:25 + | +LL | struct Wrapper u32>; + | ^^^^^^^^^^^ + +error: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:10:15 + | +LL | impl u32> Wrapper { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs index 08f6e0db31cae..14fa3b494b3fc 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.rs +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -1,7 +1,8 @@ -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete struct Checked bool>; +//~^ ERROR: using function pointers as const generic parameters fn not_one(val: usize) -> bool { val != 1 } fn not_two(val: usize) -> bool { val != 2 } @@ -13,14 +14,14 @@ fn generic(val: usize) -> bool { val != 1 } fn main() { let _: Option> = None; let _: Checked = Checked::; - let _: Checked = Checked::; //~ mismatched types + let _: Checked = Checked::; let _ = Checked::; let _ = Checked::<{generic_arg::}>; - let _ = Checked::<{generic_arg::}>; //~ mismatched types + let _ = Checked::<{generic_arg::}>; - let _ = Checked::; //~ type annotations needed + let _ = Checked::; let _ = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; - let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types + let _: Checked<{generic::}> = Checked::<{generic::}>; } diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index de41d2984a655..7aaa41eb7d7b1 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -1,46 +1,17 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/fn-const-param-infer.rs:1:12 | -LL | #![feature(const_generics, const_compare_raw_pointers)] +LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:16:31 +error: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-infer.rs:4:25 | -LL | let _: Checked = Checked::; - | ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}` - | - = note: expected type `{not_one as fn(usize) -> bool}` - found type `{not_two as fn(usize) -> bool}` - -error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:20:24 - | -LL | let _ = Checked::<{generic_arg::}>; - | ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32` - | - = note: expected fn pointer `fn(usize) -> _` - found fn item `fn(u32) -> _ {generic_arg::}` - -error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:22:23 - | -LL | let _ = Checked::; - | ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic` - -error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:25:40 - | -LL | let _: Checked<{generic::}> = Checked::<{generic::}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` - | - = note: expected type `{generic:: as fn(usize) -> bool}` - found type `{generic:: as fn(usize) -> bool}` +LL | struct Checked bool>; + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs index c498bfe2e9781..97ca9d6a44c9e 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -1,12 +1,11 @@ -// run-pass -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete const A: u32 = 3; -struct Const; +struct Const; //~ ERROR: using raw pointers as const generic parameters -impl Const

{ +impl Const

{ //~ ERROR: using raw pointers as const generic parameters fn get() -> u32 { unsafe { *P diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr index 1ffc63ffdac03..1ce8bb9c05423 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr @@ -1,11 +1,23 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/raw-ptr-const-param-deref.rs:2:12 + --> $DIR/raw-ptr-const-param-deref.rs:1:12 | -LL | #![feature(const_generics, const_compare_raw_pointers)] +LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:6:23 + | +LL | struct Const; + | ^^^^^^^^^^ + +error: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:8:15 + | +LL | impl Const

{ + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs index d7d970e952b65..237b410e073d6 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -1,9 +1,9 @@ -#![feature(const_generics, const_compare_raw_pointers)] +#![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete -struct Const; +struct Const; //~ ERROR: using raw pointers as const generic parameters fn main() { - let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types + let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>; } diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index 7a665397c1207..6e64f8a327fd5 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -1,21 +1,17 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/raw-ptr-const-param.rs:1:12 | -LL | #![feature(const_generics, const_compare_raw_pointers)] +LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:7:40 +error: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param.rs:4:23 | -LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` - | - = note: expected type `{0xf as *const u32}` - found type `{0xa as *const u32}` +LL | struct Const; + | ^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 9be1374f85d99..91c4bc8972ca5 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,17 +1,6 @@ -#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)] - fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this -// unconst and bad, will thus error in miri -const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this -// unconst and fine -const Y: usize = unsafe { 42usize as *const i32 as usize + 1 }; -// unconst and bad, will thus error in miri -const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this -// unconst and fine -const Z: i32 = unsafe { *(&1 as *const i32) }; +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be compared // unconst and bad, will thus error in miri -const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause -const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be compared diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index cc40728e6b574..dee555beca0ca 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,44 +1,20 @@ -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:6:26 +error: pointers cannot be compared in a meaningful way during const eval. + --> $DIR/const_raw_ptr_ops.rs:4:26 | LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; - | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[deny(const_err)]` on by default + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:8:27 +error: pointers cannot be compared in a meaningful way during const eval. + --> $DIR/const_raw_ptr_ops.rs:6:27 | LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; - | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants - -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:12:28 - | -LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; - | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^------- - | | - | "pointer-to-integer cast" needs an rfc before being allowed inside constants - -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:16:26 - | -LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | -------------------------^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn bytes into a pointer - -error: any use of this value will cause an error - --> $DIR/const_raw_ptr_ops.rs:17:26 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | -------------------------^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn bytes into a pointer + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs new file mode 100644 index 0000000000000..d2a7623837a23 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -0,0 +1,13 @@ +#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)] + +fn main() {} + +// unconst and fine +const Y: usize = unsafe { 42usize as *const i32 as usize + 1 }; +// unconst and bad, will thus error in miri +const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this +// unconst and fine +const Z: i32 = unsafe { *(&1 as *const i32) }; +// unconst and bad, will thus error in miri +const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause +const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr new file mode 100644 index 0000000000000..93f2261745d6f --- /dev/null +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -0,0 +1,28 @@ +error: any use of this value will cause an error + --> $DIR/const_raw_ptr_ops2.rs:8:28 + | +LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; + | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^------- + | | + | "pointer-to-integer cast" needs an rfc before being allowed inside constants + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $DIR/const_raw_ptr_ops2.rs:12:26 + | +LL | const Z2: i32 = unsafe { *(42 as *const i32) }; + | -------------------------^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn bytes into a pointer + +error: any use of this value will cause an error + --> $DIR/const_raw_ptr_ops2.rs:13:26 + | +LL | const Z3: i32 = unsafe { *(44 as *const i32) }; + | -------------------------^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn bytes into a pointer + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs index c6fb5eeab5aec..d724fe3060b21 100644 --- a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs @@ -1,4 +1,4 @@ -#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)] +#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)] fn main() { let x: &'static bool = &(42 as *const i32 == 43 as *const i32); diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 4b3fe9957002e..c5d136ea97dfa 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -12,7 +12,7 @@ LL | let _v = x + 0; warning: skipping const checks | -help: skipping check for `const_compare_raw_pointers` feature +help: skipping check that does not even have a feature gate --> $DIR/ptr_arith.rs:9:14 | LL | let _v = x == x; diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index bbefff27d7f68..28fba1d306139 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -1,10 +1,8 @@ -// gate-test-const_compare_raw_pointers - static FOO: i32 = 42; static BAR: i32 = 42; static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; -//~^ ERROR comparing raw pointers inside static +//~^ ERROR pointers cannot be compared in a meaningful way during const eval fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 20c8622f33726..748126f74407c 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,12 +1,11 @@ -error[E0658]: comparing raw pointers inside static - --> $DIR/E0395.rs:6:29 +error: pointers cannot be compared in a meaningful way during const eval. + --> $DIR/E0395.rs:4:29 | LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs index 1ab11ce3b4423..dc602ba7e6f21 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs @@ -1,9 +1,9 @@ struct ConstFn; //~^ ERROR const generics are unstable -//~^^ ERROR using function pointers as const generic parameters is unstable +//~^^ ERROR using function pointers as const generic parameters is forbidden struct ConstPtr; //~^ ERROR const generics are unstable -//~^^ ERROR using raw pointers as const generic parameters is unstable +//~^^ ERROR using raw pointers as const generic parameters is forbidden fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index dc7ef55e7ab99..b2c96d3810f98 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -16,23 +16,17 @@ LL | struct ConstPtr; = note: see issue #44580 for more information = help: add `#![feature(const_generics)]` to the crate attributes to enable -error[E0658]: using function pointers as const generic parameters is unstable +error: using function pointers as const generic parameters is forbidden --> $DIR/feature-gate-const_generics-ptr.rs:1:25 | LL | struct ConstFn; | ^^^^ - | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable -error[E0658]: using raw pointers as const generic parameters is unstable +error: using raw pointers as const generic parameters is forbidden --> $DIR/feature-gate-const_generics-ptr.rs:5:26 | LL | struct ConstPtr; | ^^^^^^^^^^ - | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs index 36a69cf4c22ff..cb0dfcfa953e4 100644 --- a/src/test/ui/issues/issue-25826.rs +++ b/src/test/ui/issues/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR comparing raw pointers inside constant + //~^ ERROR pointers cannot be compared in a meaningful way during const eval println!("{}", A); } diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index 3a5a6b509ba9d..b3692098341e7 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,12 +1,11 @@ -error[E0658]: comparing raw pointers inside constant +error: pointers cannot be compared in a meaningful way during const eval. --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #53020 for more information - = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs index d9d85ee913266..963d892931a75 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs @@ -1,13 +1,13 @@ #![stable(feature = "foo", since = "1.33.0")] #![feature(staged_api)] -#![feature(const_compare_raw_pointers)] +#![feature(const_raw_ptr_deref)] #![feature(const_fn)] #[stable(feature = "foo", since = "1.33.0")] #[rustc_const_unstable(feature = "const_foo", issue = "none")] -const fn unstable(a: *const i32, b: *const i32) -> bool { - a == b - //~^ pointer operation is unsafe +const fn unstable(a: *const i32, b: i32) -> bool { + *a == b + //~^ dereference of raw pointer is unsafe } fn main() {} diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr index d8f3737c8f541..4642a7a5fc9f8 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr @@ -1,10 +1,10 @@ -error[E0133]: pointer operation is unsafe and requires unsafe function or block +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/unsafe-unstable-const-fn.rs:9:5 | -LL | a == b - | ^^^^^^ pointer operation +LL | *a == b + | ^^ dereference of raw pointer | - = note: operations on pointers in constants + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: aborting due to previous error From e09b62033926dff8bfedca35b93e0dfbf767749f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 16 Jun 2020 10:37:34 +0200 Subject: [PATCH 03/30] Add fuzzy pointer comparison intrinsics --- src/libcore/intrinsics.rs | 10 +++ src/libcore/lib.rs | 1 + src/libcore/ptr/const_ptr.rs | 66 +++++++++++++++++++ src/libcore/ptr/mut_ptr.rs | 66 +++++++++++++++++++ src/libcore/slice/mod.rs | 50 +++++++++++++- src/librustc_codegen_llvm/intrinsic.rs | 14 +++- src/librustc_mir/interpret/intrinsics.rs | 5 ++ .../transform/check_consts/ops.rs | 22 ++++--- src/librustc_span/symbol.rs | 2 + src/librustc_typeck/check/intrinsic.rs | 9 ++- .../const-eval/const_raw_ptr_ops.stderr | 10 +-- src/test/ui/consts/miri_unleashed/slice_eq.rs | 17 +++++ src/test/ui/error-codes/E0395.stderr | 5 +- src/test/ui/issues/issue-25826.stderr | 5 +- 14 files changed, 260 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/consts/miri_unleashed/slice_eq.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 9061145a695f8..4648f762bab42 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1948,6 +1948,16 @@ extern "rust-intrinsic" { #[cfg(not(bootstrap))] #[lang = "count_code_region"] pub fn count_code_region(index: u32); + + /// See documentation of `<*const T>::guaranteed_eq` for details. + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(not(bootstrap))] + pub fn ptr_guaranteed_eq(ptr: *const T, other: *const T) -> bool; + + /// See documentation of `<*const T>::guaranteed_ne` for details. + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(not(bootstrap))] + pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; } // Some functions are defined here because they accidentally got made diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fe05e914e6d44..b2f6f789603a9 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -87,6 +87,7 @@ #![feature(const_generics)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] +#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))] #![feature(const_result)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index e39d18d7733a2..0e2e6848416b6 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -295,6 +295,72 @@ impl *const T { intrinsics::ptr_offset_from(self, origin) } + /// Returns whether two pointers are guaranteed equal. + /// + /// At runtime this function behaves like `self == other`. + /// However, in some contexts (e.g., compile-time evaluation), + /// it is not always possible to determine equality of two pointers, so this function may + /// spuriously return `false` for pointers that later actually turn out to be equal. + /// But when it returns `true`, the pointers are guaranteed to be equal. + /// + /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer + /// comparisons for which both functions return `false`. + /// + /// [`guaranteed_ne`]: #method.guaranteed_ne + /// + /// The return value may change depending on the compiler version and unsafe code may not + /// rely on the result of this function for soundness. It is suggested to only use this function + /// for performance optimizations where spurious `false` return values by this function do not + /// affect the outcome, but just the performance. + /// The consequences of using this method to make runtime and compile-time code behave + /// differently have not been explored. This method should not be used to introduce such + /// differences, and it should also not be stabilized before we have a better understanding + /// of this issue. + /// ``` + #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[inline] + #[cfg(not(bootstrap))] + pub const fn guaranteed_eq(self, other: *const T) -> bool + where + T: Sized, + { + intrinsics::ptr_guaranteed_eq(self, other) + } + + /// Returns whether two pointers are guaranteed not equal. + /// + /// At runtime this function behaves like `self != other`. + /// However, in some contexts (e.g., compile-time evaluation), + /// it is not always possible to determine the inequality of two pointers, so this function may + /// spuriously return `false` for pointers that later actually turn out to be inequal. + /// But when it returns `true`, the pointers are guaranteed to be inequal. + /// + /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer + /// comparisons for which both functions return `false`. + /// + /// [`guaranteed_eq`]: #method.guaranteed_eq + /// + /// The return value may change depending on the compiler version and unsafe code may not + /// rely on the result of this function for soundness. It is suggested to only use this function + /// for performance optimizations where spurious `false` return values by this function do not + /// affect the outcome, but just the performance. + /// The consequences of using this method to make runtime and compile-time code behave + /// differently have not been explored. This method should not be used to introduce such + /// differences, and it should also not be stabilized before we have a better understanding + /// of this issue. + /// ``` + #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[inline] + #[cfg(not(bootstrap))] + pub const fn guaranteed_ne(self, other: *const T) -> bool + where + T: Sized, + { + intrinsics::ptr_guaranteed_ne(self, other) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. /// diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 40b5e4e22340e..67ace1f72a0ab 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -273,6 +273,72 @@ impl *mut T { if self.is_null() { None } else { Some(&mut *self) } } + /// Returns whether two pointers are guaranteed equal. + /// + /// At runtime this function behaves like `self == other`. + /// However, in some contexts (e.g., compile-time evaluation), + /// it is not always possible to determine equality of two pointers, so this function may + /// spuriously return `false` for pointers that later actually turn out to be equal. + /// But when it returns `true`, the pointers are guaranteed to be equal. + /// + /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer + /// comparisons for which both functions return `false`. + /// + /// [`guaranteed_ne`]: #method.guaranteed_ne + /// + /// The return value may change depending on the compiler version and unsafe code may not + /// rely on the result of this function for soundness. It is suggested to only use this function + /// for performance optimizations where spurious `false` return values by this function do not + /// affect the outcome, but just the performance. + /// The consequences of using this method to make runtime and compile-time code behave + /// differently have not been explored. This method should not be used to introduce such + /// differences, and it should also not be stabilized before we have a better understanding + /// of this issue. + /// ``` + #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[inline] + #[cfg(not(bootstrap))] + pub const fn guaranteed_eq(self, other: *mut T) -> bool + where + T: Sized, + { + intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _) + } + + /// Returns whether two pointers are guaranteed not equal. + /// + /// At runtime this function behaves like `self != other`. + /// However, in some contexts (e.g., compile-time evaluation), + /// it is not always possible to determine the inequality of two pointers, so this function may + /// spuriously return `false` for pointers that later actually turn out to be inequal. + /// But when it returns `true`, the pointers are guaranteed to be inequal. + /// + /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer + /// comparisons for which both functions return `false`. + /// + /// [`guaranteed_eq`]: #method.guaranteed_eq + /// + /// The return value may change depending on the compiler version and unsafe code may not + /// rely on the result of this function for soundness. It is suggested to only use this function + /// for performance optimizations where spurious `false` return values by this function do not + /// affect the outcome, but just the performance. + /// The consequences of using this method to make runtime and compile-time code behave + /// differently have not been explored. This method should not be used to introduce such + /// differences, and it should also not be stabilized before we have a better understanding + /// of this issue. + /// ``` + #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[inline] + #[cfg(not(bootstrap))] + pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool + where + T: Sized, + { + intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes is divided by `mem::size_of::()`. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 21ba2b5abcfb6..12932b06d32d4 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5946,7 +5946,8 @@ where } } -// Use an equal-pointer optimization when types are `Eq` +// Remove after boostrap bump +#[cfg(bootstrap)] impl SlicePartialEq for [A] where A: PartialEq + Eq, @@ -5964,7 +5965,8 @@ where } } -// Use memcmp for bytewise equality when the types allow +// Remove after boostrap bump +#[cfg(bootstrap)] impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality, @@ -5983,6 +5985,50 @@ where } } +// Use an equal-pointer optimization when types are `Eq` +#[cfg(not(bootstrap))] +impl SlicePartialEq for [A] +where + A: PartialEq + Eq, +{ + default fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr()) { + return true; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use memcmp for bytewise equality when the types allow +#[cfg(not(bootstrap))] +impl SlicePartialEq for [A] +where + A: PartialEq + BytewiseEquality, +{ + fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr()) { + return true; + } + unsafe { + let size = mem::size_of_val(self); + memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + } + } +} + #[doc(hidden)] // intermediate trait for specialization of slice's PartialOrd trait SlicePartialOrd: Sized { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 95465939070a0..78c29588e2e1b 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -12,7 +12,7 @@ use log::debug; use rustc_ast::ast; use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; -use rustc_codegen_ssa::common::TypeKind; +use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -731,6 +731,18 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } + "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = self.ptrtoint(a, self.type_isize()); + let b = self.ptrtoint(b, self.type_isize()); + if name == "ptr_guaranteed_eq" { + self.icmp(IntPredicate::IntEQ, a, b) + } else { + self.icmp(IntPredicate::IntNE, a, b) + } + } + "ptr_offset_from" => { let ty = substs.type_at(0); let pointee_size = self.size_of(ty); diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ac28ccd181520..1b4113a61b451 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -291,6 +291,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); self.write_scalar(offset_ptr, dest)?; } + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + // FIXME: return `true` for at least some comparisons where we can reliably + // determine the result of runtime (in)equality tests at compile-time. + self.write_scalar(Scalar::from_bool(false), dest)?; + } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index f09b598ce069d..9f005c0b4dda8 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -290,17 +290,23 @@ impl NonConstOp for RawPtrComparison { "pointers cannot be compared in a meaningful way during const eval.", ); err.note( - "It is conceptually impossible for const eval to know in all cases whether two \ - pointers are equal. While sometimes it is clear (the address of a static item \ - is never equal to the address of another static item), comparing an integer \ - address with any allocation's address is impossible to do at compile-time.", + "see issue #53020 \ + for more information", ); err.note( - "That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all \ - comparisons where CTFE isn't sure whether two addresses are equal. The mirror \ - intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't \ - sure whether two addresses are inequal.", + "It is conceptually impossible for const eval to know in all cases whether two \ + pointers are equal. While sometimes it is clear (the address of a non-zst static item \ + is never equal to the address of another non-zst static item), comparing an integer \ + address with any allocation's address is impossible to do at compile-time.", ); + if ccx.tcx.sess.parse_sess.unstable_features.is_nightly_build() { + err.note( + "That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` \ + for all comparisons where CTFE is sure that two addresses are equal. The mirror \ + intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where \ + CTFE is sure that two addresses are inequal.", + ); + } err.emit(); } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 970a26325926c..06d1f36622b94 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -588,6 +588,8 @@ symbols! { proc_macro_non_items, proc_macro_path_invoc, profiler_runtime, + ptr_guaranteed_eq, + ptr_guaranteed_ne, ptr_offset_from, pub_restricted, pure, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3ec6973a17d56..ef6c7c14404a7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add" | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely" - | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => { - hir::Unsafety::Normal - } + | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32" + | "maxnumf64" | "type_name" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } @@ -258,6 +257,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])) } + "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { + (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) + } + "ptr_offset_from" => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) } diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index dee555beca0ca..6f27ac74ade83 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: pointers cannot be compared in a meaningful way during const eval. --> $DIR/const_raw_ptr_ops.rs:6:27 @@ -13,8 +14,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs new file mode 100644 index 0000000000000..fd843105daf2a --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/slice_eq.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +// run-pass + +#![feature(const_raw_ptr_comparison)] + +const EMPTY_SLICE: &[i32] = &[]; +const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _); +const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _); +const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _); +const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _); + +fn main() { + assert!(!EMPTY_EQ); + assert!(!EMPTY_EQ2); + assert!(!EMPTY_NE); + assert!(!EMPTY_NE2); +} diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 748126f74407c..62949cf15e13c 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index b3692098341e7..cb24aede81a2c 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -4,8 +4,9 @@ error: pointers cannot be compared in a meaningful way during const eval. LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a static item is never equal to the address of another static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `ptr_maybe_eq` intrinsic which returns `true` for all comparisons where CTFE isn't sure whether two addresses are equal. The mirror intrinsic `ptr_maybe_ne` returns `true` for all comparisons where CTFE isn't sure whether two addresses are inequal. + = note: see issue #53020 for more information + = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. + = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error From 84f1d73182f4882518d5eef067b18b49b49e985a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 18 Jun 2020 10:06:57 +0200 Subject: [PATCH 04/30] Tidy got confused on `rustc_const_unstable` `issue`s --- src/libcore/intrinsics.rs | 8 ++++---- src/tools/tidy/src/features.rs | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 4648f762bab42..2b34e98028232 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -11,7 +11,7 @@ //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to //! `librustc_mir/interpret/intrinsics.rs` and add a -//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. +//! `#[rustc_const_unstable(feature = "foo2", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done @@ -1012,7 +1012,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::any::type_name`](../../std/any/fn.type_name.html) - #[rustc_const_unstable(feature = "const_type_name", issue = "none")] + #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This @@ -1021,7 +1021,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of) - #[rustc_const_unstable(feature = "const_type_id", issue = "none")] + #[rustc_const_unstable(feature = "const_type_id", issue = "41875")] pub fn type_id() -> u64; /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: @@ -1931,7 +1931,7 @@ extern "rust-intrinsic" { pub fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")] pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// Internal hook used by Miri to implement unwinding. diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d9320e9147cff..3fa637b5a696f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -444,10 +444,7 @@ fn map_lib_features( level: Status::Unstable, since: None, has_gate_test: false, - // FIXME(#57563): #57563 is now used as a common tracking issue, - // although we would like to have specific tracking issues for each - // `rustc_const_unstable` in the future. - tracking_issue: NonZeroU32::new(57563), + tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none), }; mf(Ok((feature_name, feature)), file, i + 1); continue; From e75fbaee45a24816e8e2b27cd9f8896766aee6e3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 19 Jun 2020 14:46:04 -0500 Subject: [PATCH 05/30] add second message for livedrop errors --- src/librustc_mir/transform/check_consts/ops.rs | 13 ++++++++----- .../transform/check_consts/post_drop_elaboration.rs | 2 +- .../transform/check_consts/validation.rs | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index d5059c98c9511..7791ae7fa12aa 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -160,17 +160,20 @@ pub struct InlineAsm; impl NonConstOp for InlineAsm {} #[derive(Debug)] -pub struct LiveDrop; +pub struct LiveDrop(pub Option); impl NonConstOp for LiveDrop { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - struct_span_err!( + let mut diagnostic = struct_span_err!( ccx.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time" - ) - .span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())) - .emit(); + ); + diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); + if let Some(span) = self.0 { + diagnostic.span_label(span, "value is dropped here"); + } + diagnostic.emit(); } } diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs index 226e0e2049ebd..b17ee53bda81f 100644 --- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs +++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs @@ -58,7 +58,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop, span); + ops::non_const(self.ccx, ops::LiveDrop(None), span); } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 428a74bcdcbfb..e7886c50b7a32 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -588,7 +588,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { }; if needs_drop { - self.check_op_spanned(ops::LiveDrop, err_span); + self.check_op_spanned( + ops::LiveDrop(Some(terminator.source_info.span)), + err_span, + ); } } From 562f4967b4ce7e859b807fc022040bbb22d1f70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Jun 2020 13:57:33 -0700 Subject: [PATCH 06/30] Account for multiple impl/dyn Trait in return type when suggesting `'_` --- .../nice_region_error/find_anon_type.rs | 2 +- .../nice_region_error/named_anon_conflict.rs | 13 ++- .../nice_region_error/static_impl_trait.rs | 76 +++++++++------ src/librustc_middle/ty/context.rs | 32 ++----- src/librustc_middle/ty/diagnostics.rs | 31 ++++-- ...t_outlive_least_region_or_bound.nll.stderr | 16 +++- .../must_outlive_least_region_or_bound.rs | 4 + .../must_outlive_least_region_or_bound.stderr | 45 ++++++++- ...types_pin_lifetime_impl_trait-async.stderr | 5 + ...ait-object-nested-in-impl-trait.nll.stderr | 53 +++++++++++ .../trait-object-nested-in-impl-trait.rs | 68 +++++++++++++ .../trait-object-nested-in-impl-trait.stderr | 95 +++++++++++++++++++ 12 files changed, 363 insertions(+), 77 deletions(-) create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs index de71363cbde5c..6677c0e59f63a 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -26,7 +26,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { &self, region: Region<'tcx>, br: &ty::BoundRegion, - ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> { + ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> { if let Some(anon_reg) = self.tcx().is_suitable_region(region) { let def_id = anon_reg.def_id; if let Some(def_id) = def_id.as_local() { diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index a56401ebb90f0..7c8ba834dcdcb 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -2,7 +2,8 @@ //! where one region is named and the other is anonymous. use crate::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir::{FnRetTy, TyKind}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::FnRetTy; use rustc_middle::ty; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -80,12 +81,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let FnRetTy::Return(ty) = &fndecl.output { - let mut v = ty::TraitObjectVisitor(vec![]); - rustc_hir::intravisit::walk_ty(&mut v, ty); + let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir()); + v.visit_ty(ty); debug!("try_report_named_anon_conflict: ret ty {:?}", ty); if sub == &ty::ReStatic - && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1) + && v.0 + .into_iter() + .filter(|t| t.span.desugaring_kind().is_none()) + .next() + .is_some() { debug!("try_report_named_anon_conflict: impl Trait + 'static"); // This is an `impl Trait` or `dyn Trait` return that evaluates de need of diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 82feebc80292a..20b275ea34af0 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -26,8 +26,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); - let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; - debug!("try_report_static_impl_trait: fn_return={:?}", fn_return); + let fn_returns = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id); + if fn_returns.is_empty() { + return None; + } + debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); if **sub_r == RegionKind::ReStatic { let sp = var_origin.span(); let return_sp = sub_origin.span(); @@ -98,25 +101,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); } - // only apply this suggestion onto functions with - // explicit non-desugar'able return. - if fn_return.span.desugaring_kind().is_none() { - // FIXME: account for the need of parens in `&(dyn Trait + '_)` - - let consider = "consider changing the"; - let declare = "to declare that the"; - let arg = match param_info.param.pat.simple_ident() { - Some(simple_ident) => format!("argument `{}`", simple_ident), - None => "the argument".to_string(), - }; - let explicit = - format!("you can add an explicit `{}` lifetime bound", lifetime_name); - let explicit_static = - format!("explicit `'static` bound to the lifetime of {}", arg); - let captures = format!("captures data from {}", arg); - let add_static_bound = - "alternatively, add an explicit `'static` bound to this reference"; - let plus_lt = format!(" + {}", lifetime_name); + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param_info.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = + format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = + format!("explicit `'static` bound to the lifetime of {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = + "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + for fn_return in fn_returns { + if fn_return.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + continue; + } match fn_return.kind { TyKind::OpaqueDef(item_id, _) => { let item = self.tcx().hir().item(item_id.id); @@ -143,7 +147,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_suggestion_verbose( span, &format!("{} `impl Trait`'s {}", consider, explicit_static), - lifetime_name, + lifetime_name.clone(), Applicability::MaybeIncorrect, ); err.span_suggestion_verbose( @@ -152,6 +156,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { param_info.param_ty.to_string(), Applicability::MaybeIncorrect, ); + } else if let Some(_) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { name, span, .. }) + if name.ident().to_string() == lifetime_name => + { + Some(*span) + } + _ => None, + }) + .next() + { } else { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), @@ -161,10 +178,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { captures = captures, explicit = explicit, ), - plus_lt, + plus_lt.clone(), Applicability::MaybeIncorrect, ); - }; + } } TyKind::TraitObject(_, lt) => match lt.name { LifetimeName::ImplicitObjectLifetimeDefault => { @@ -176,15 +193,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { captures = captures, explicit = explicit, ), - plus_lt, + plus_lt.clone(), Applicability::MaybeIncorrect, ); } - _ => { + name if name.ident().to_string() != lifetime_name => { + // With this check we avoid suggesting redundant bounds. This + // would happen if there are nested impl/dyn traits and only + // one of them has the bound we'd suggest already there, like + // in `impl Foo + '_`. err.span_suggestion_verbose( lt.span, &format!("{} trait object's {}", consider, explicit_static), - lifetime_name, + lifetime_name.clone(), Applicability::MaybeIncorrect, ); err.span_suggestion_verbose( @@ -194,6 +215,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { Applicability::MaybeIncorrect, ); } + _ => {} }, _ => {} } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 62d6de2d71e6d..73374bb1e8443 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -37,6 +37,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::{self, PanicLocationLangItem}; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; @@ -1405,10 +1406,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn return_type_impl_or_dyn_trait( - &self, - scope_def_id: DefId, - ) -> Option<&'tcx hir::Ty<'tcx>> { + pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); let hir_output = match self.hir().get(hir_id) { Node::Item(hir::Item { @@ -1444,30 +1442,12 @@ impl<'tcx> TyCtxt<'tcx> { ), .. }) => ty, - _ => return None, + _ => return vec![], }; - let ret_ty = self.type_of(scope_def_id); - match ret_ty.kind { - ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); - let output = self.erase_late_bound_regions(&sig.output()); - if output.is_impl_trait() { - let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); - if let hir::FnRetTy::Return(ty) = fn_decl.output { - return Some(ty); - } - } else { - let mut v = TraitObjectVisitor(vec![]); - rustc_hir::intravisit::walk_ty(&mut v, hir_output); - if v.0.len() == 1 { - return Some(v.0[0]); - } - } - None - } - _ => None, - } + let mut v = TraitObjectVisitor(vec![], self.hir()); + v.visit_ty(hir_output); + v.0 } pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> { diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index a2812e117ed39..b22727bdd7587 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -236,7 +236,9 @@ pub fn suggest_constraining_type_param( } } -pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>); +/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. +pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>); + impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { type Map = rustc_hir::intravisit::ErasedMap<'v>; @@ -245,15 +247,24 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { } fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - if let hir::TyKind::TraitObject( - _, - hir::Lifetime { - name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, - .. - }, - ) = ty.kind - { - self.0.push(ty); + match ty.kind { + hir::TyKind::TraitObject( + _, + hir::Lifetime { + name: + hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, + .. + }, + ) => { + self.0.push(ty); + } + hir::TyKind::OpaqueDef(item_id, _) => { + self.0.push(ty); + let item = self.1.expect_item(item_id.id); + hir::intravisit::walk_item(self, item); + } + _ => {} } + hir::intravisit::walk_ty(self, ty); } } diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index ca9ca8a9debe2..3b339c5c3d7fc 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -53,7 +53,15 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:33:69 + --> $DIR/must_outlive_least_region_or_bound.rs:30:24 + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:37:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -62,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:38:61 + --> $DIR/must_outlive_least_region_or_bound.rs:42:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` @@ -72,14 +80,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 = help: consider adding the following bound: `'b: 'a` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:43:51 + --> $DIR/must_outlive_least_region_or_bound.rs:47:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | ^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0310, E0621. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 837244b022721..9bf86fa66cded 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -27,6 +27,10 @@ fn elided4(x: &i32) -> Box { Box::new(x) } fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } //~^ ERROR cannot infer an appropriate lifetime +fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } +//~^ ERROR cannot infer an appropriate lifetime +//~| ERROR cannot infer an appropriate lifetime + trait LifetimeTrait<'a> {} impl<'a> LifetimeTrait<'a> for &'a i32 {} diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index e1fa4f02b6fcf..ffadcaae08e05 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -87,13 +87,48 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` error[E0759]: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:33:69 + --> $DIR/must_outlive_least_region_or_bound.rs:30:65 + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static` + | +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | ^^^^ +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box, impl Debug + '_) { (Box::new(x), x) } + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:30:69 + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:30:41 + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | ^^^^^^^^^^ +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } + | ^^^^ +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided5(x: &i32) -> (Box, impl Debug + '_) { (Box::new(x), x) } + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:37:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ------- this data with lifetime `'a`... ^ ...is captured here... | note: ...and is required to live as long as `'static` here - --> $DIR/must_outlive_least_region_or_bound.rs:33:34 + --> $DIR/must_outlive_least_region_or_bound.rs:37:34 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x | ^^^^^^^^^^^^ error[E0623]: lifetime mismatch - --> $DIR/must_outlive_least_region_or_bound.rs:38:61 + --> $DIR/must_outlive_least_region_or_bound.rs:42:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | ------- ^^^^^^^^^^^^^^^^ @@ -116,7 +151,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 | this parameter and the return type are declared with different lifetimes... error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:43:51 + --> $DIR/must_outlive_least_region_or_bound.rs:47:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds @@ -181,7 +216,7 @@ help: alternatively, add an explicit `'static` bound to this reference LL | fn explicit4<'a>(x: &'static i32) -> Box { Box::new(x) } | ^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0310, E0621, E0623, E0759. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 88bd990b1e81b..f2fbb0ba7d755 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -6,6 +6,11 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } | | | | | this data with an anonymous lifetime `'_`... | ...is captured here... + | +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound + | +LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self } + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr new file mode 100644 index 0000000000000..2407d13714a2a --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr @@ -0,0 +1,53 @@ +error: lifetime may not live long enough + --> $DIR/trait-object-nested-in-impl-trait.rs:27:23 + | +LL | fn iter(&self) -> impl Iterator> { + | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | +help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/trait-object-nested-in-impl-trait.rs:39:9 + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | - let's call the lifetime of this reference `'1` +LL | / Iter { +LL | | current: None, +LL | | remaining: self.0.iter(), +LL | | } + | |_________^ returning this value requires that `'1` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/trait-object-nested-in-impl-trait.rs:50:9 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | -- lifetime `'a` defined here +LL | / Iter { +LL | | current: None, +LL | | remaining: self.0.iter(), +LL | | } + | |_________^ returning this value requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + +error: lifetime may not live long enough + --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> { + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + | | + | lifetime `'a` defined here + | + = help: consider replacing `'a` with `'static` +help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs new file mode 100644 index 0000000000000..f78edb1c83a4c --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs @@ -0,0 +1,68 @@ +trait Foo {} +impl<'a, T: Foo> Foo for &'a T {} +impl Foo for Box {} + +struct Iter<'a, T> { + current: Option>, + remaining: T, +} + +impl<'a, T> Iterator for Iter<'a, T> +where + T: Iterator, + T::Item: Foo + 'a, +{ + type Item = Box; + + fn next(&mut self) -> Option { + let result = self.current.take(); + self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _); + result + } +} + +struct Bar(Vec>); + +impl Bar { + fn iter(&self) -> impl Iterator> { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Baz(Vec>); + +impl Baz { + fn iter(&self) -> impl Iterator> + '_ { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Bat(Vec>); + +impl Bat { + fn iter<'a>(&'a self) -> impl Iterator> + 'a { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Ban(Vec>); + +impl Ban { + fn iter<'a>(&'a self) -> impl Iterator> { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr new file mode 100644 index 0000000000000..1257e9b172cf7 --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -0,0 +1,95 @@ +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/trait-object-nested-in-impl-trait.rs:30:31 + | +LL | fn iter(&self) -> impl Iterator> { + | ----- this data with an anonymous lifetime `'_`... +... +LL | remaining: self.0.iter(), + | ------ ^^^^ + | | + | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/trait-object-nested-in-impl-trait.rs:27:23 + | +LL | fn iter(&self) -> impl Iterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ^^^^ +help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound + | +LL | fn iter(&self) -> impl Iterator> { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/trait-object-nested-in-impl-trait.rs:41:31 + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ----- this data with an anonymous lifetime `'_`... +... +LL | remaining: self.0.iter(), + | ------ ^^^^ + | | + | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/trait-object-nested-in-impl-trait.rs:38:23 + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/trait-object-nested-in-impl-trait.rs:52:31 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | -------- this data with lifetime `'a`... +... +LL | remaining: self.0.iter(), + | ------ ^^^^ + | | + | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/trait-object-nested-in-impl-trait.rs:49:30 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/trait-object-nested-in-impl-trait.rs:63:31 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> { + | -------- this data with lifetime `'a`... +... +LL | remaining: self.0.iter(), + | ------ ^^^^ + | | + | ...is captured here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 + | +LL | fn iter<'a>(&'a self) -> impl Iterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound + | +LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { + | ^^^^ +help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound + | +LL | fn iter<'a>(&'a self) -> impl Iterator> { + | ^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0759`. From 0624a5a063c0282811ac63b13861abb768f3f9c7 Mon Sep 17 00:00:00 2001 From: Rakshith Ravi Date: Sat, 20 Jun 2020 13:00:16 +0530 Subject: [PATCH 07/30] Squashed all commits --- src/librustc_typeck/astconv.rs | 73 +++++++++++++++++-- .../const-arg-type-arg-misordered.stderr | 1 + .../ui/suggestions/suggest-move-types.stderr | 2 + 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f1dc7e5390629..1b06542871fc3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -8,8 +8,7 @@ use crate::collect::PlaceholderHirTyCollector; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; -use rustc_ast::ast::ParamKindOrd; -use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError}; @@ -27,7 +26,7 @@ use rustc_middle::ty::{GenericParamDef, GenericParamDefKind}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits; @@ -475,7 +474,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Report an error that a generic argument did not match the generic parameter that was /// expected. - fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) { + fn generic_arg_mismatch_err( + sess: &Session, + arg: &GenericArg<'_>, + kind: &'static str, + help: Option<&str>, + ) { let mut err = struct_span_err!( sess, arg.span(), @@ -503,6 +507,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let (first, last) = if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; err.note(&format!("{} arguments must be provided before {} arguments", first, last)); + + if let Some(help) = help { + err.help(help); + } err.emit(); } @@ -648,7 +656,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if arg_count.correct.is_ok() && arg_count.explicit_late_bound == ExplicitLateBound::No { - Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); + // We're going to iterate over the parameters to sort them out, and + // show that order to the user as a possible order for the parameters + let mut param_types_present = defs + .params + .clone() + .into_iter() + .map(|param| { + ( + match param.kind { + GenericParamDefKind::Lifetime => { + ParamKindOrd::Lifetime + } + GenericParamDefKind::Type { .. } => { + ParamKindOrd::Type + } + GenericParamDefKind::Const => { + ParamKindOrd::Const + } + }, + param, + ) + }) + .collect::>(); + param_types_present.sort_by_key(|(ord, _)| *ord); + let (mut param_types_present, ordered_params): ( + Vec, + Vec, + ) = param_types_present.into_iter().unzip(); + param_types_present.dedup(); + + Self::generic_arg_mismatch_err( + tcx.sess, + arg, + kind.descr(), + Some(&format!( + "reorder the arguments: {}: `<{}>`", + param_types_present + .into_iter() + .map(|ord| format!("{}s", ord.to_string())) + .collect::>() + .join(", then "), + ordered_params + .into_iter() + .filter_map(|param| { + if param.name == kw::SelfUpper { + None + } else { + Some(param.name.to_string()) + } + }) + .collect::>() + .join(", ") + )), + ); } // We've reported the error, but we want to make sure that this @@ -680,7 +741,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(kind, "lifetime"); let provided = force_infer_lt.expect("lifetimes ought to have been inferred"); - Self::generic_arg_mismatch_err(tcx.sess, provided, kind); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None); } break; diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr index ad38b632b75f0..4a6241de1b453 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr @@ -14,6 +14,7 @@ LL | fn foo() -> Array { | ^ | = note: type arguments must be provided before constant arguments + = help: reorder the arguments: types, then consts: `` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 96f1656bae4ac..3c2226574ee9e 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -125,6 +125,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime` error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:82:56 @@ -133,6 +134,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime` error: aborting due to 12 previous errors From 9e88b48133c703c04780a9474c029b4398ca3260 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 13:25:55 +0200 Subject: [PATCH 08/30] Refer just to the issue in the raw ptr cmp diagnostic instead of explaining everything in the diagnostic --- src/librustc_mir/transform/check_consts/ops.rs | 16 +--------------- .../ui/consts/const-eval/const_raw_ptr_ops.rs | 4 ++-- .../consts/const-eval/const_raw_ptr_ops.stderr | 8 ++------ src/test/ui/error-codes/E0395.rs | 2 +- src/test/ui/error-codes/E0395.stderr | 4 +--- src/test/ui/issues/issue-25826.rs | 2 +- src/test/ui/issues/issue-25826.stderr | 4 +--- 7 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 9f005c0b4dda8..e1a040b2e0ea5 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -287,26 +287,12 @@ impl NonConstOp for RawPtrComparison { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let mut err = ccx.tcx.sess.struct_span_err( span, - "pointers cannot be compared in a meaningful way during const eval.", + "pointers cannot be reliably compared during const eval.", ); err.note( "see issue #53020 \ for more information", ); - err.note( - "It is conceptually impossible for const eval to know in all cases whether two \ - pointers are equal. While sometimes it is clear (the address of a non-zst static item \ - is never equal to the address of another non-zst static item), comparing an integer \ - address with any allocation's address is impossible to do at compile-time.", - ); - if ccx.tcx.sess.parse_sess.unstable_features.is_nightly_build() { - err.note( - "That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` \ - for all comparisons where CTFE is sure that two addresses are equal. The mirror \ - intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where \ - CTFE is sure that two addresses are inequal.", - ); - } err.emit(); } } diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 91c4bc8972ca5..083ebfdd4da3f 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,6 +1,6 @@ fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be compared +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably compared // unconst and bad, will thus error in miri -const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be compared +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably compared diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 6f27ac74ade83..21d3f5e7e8536 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,22 +1,18 @@ -error: pointers cannot be compared in a meaningful way during const eval. +error: pointers cannot be reliably compared during const eval. --> $DIR/const_raw_ptr_ops.rs:4:26 | LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. -error: pointers cannot be compared in a meaningful way during const eval. +error: pointers cannot be reliably compared during const eval. --> $DIR/const_raw_ptr_ops.rs:6:27 | LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index 28fba1d306139..d2edd97efb232 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -2,7 +2,7 @@ static FOO: i32 = 42; static BAR: i32 = 42; static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; -//~^ ERROR pointers cannot be compared in a meaningful way during const eval +//~^ ERROR pointers cannot be reliably compared during const eval fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 62949cf15e13c..674cc69645029 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,12 +1,10 @@ -error: pointers cannot be compared in a meaningful way during const eval. +error: pointers cannot be reliably compared during const eval. --> $DIR/E0395.rs:4:29 | LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/issues/issue-25826.rs index cb0dfcfa953e4..d1093c205798a 100644 --- a/src/test/ui/issues/issue-25826.rs +++ b/src/test/ui/issues/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR pointers cannot be compared in a meaningful way during const eval + //~^ ERROR pointers cannot be reliably compared during const eval println!("{}", A); } diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index cb24aede81a2c..67d1b3ab9bed6 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,12 +1,10 @@ -error: pointers cannot be compared in a meaningful way during const eval. +error: pointers cannot be reliably compared during const eval. --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53020 for more information - = note: It is conceptually impossible for const eval to know in all cases whether two pointers are equal. While sometimes it is clear (the address of a non-zst static item is never equal to the address of another non-zst static item), comparing an integer address with any allocation's address is impossible to do at compile-time. - = note: That said, there's the `<*const T>::guaranteed_eq` intrinsic which returns `true` for all comparisons where CTFE is sure that two addresses are equal. The mirror intrinsic `<*const T>::guaranteed_ne` returns `true` for all comparisons where CTFE is sure that two addresses are inequal. error: aborting due to previous error From 53686b91caac6c6782b8d2a41675f4f0941aa254 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 14:14:30 +0200 Subject: [PATCH 09/30] Satisfy tidy --- src/liballoc/raw_vec.rs | 2 +- src/libcore/intrinsics.rs | 2 +- src/librustc_mir/transform/check_consts/ops.rs | 8 ++++---- src/test/ui/consts/const-eval/const_raw_ptr_ops.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 805dbfe277584..87e73a1b91e69 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -60,7 +60,7 @@ impl RawVec { /// `#[rustc_force_min_const_fn]` attribute which requires conformance /// with `min_const_fn` but does not necessarily allow calling it in /// `stable(...) const fn` / user code not enabling `foo` when - /// `#[rustc_const_unstable(feature = "foo", ..)]` is present. + /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present. pub const NEW: Self = Self::new(); /// Creates the biggest possible `RawVec` (on the system heap) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2b34e98028232..50e321f9c7158 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -11,7 +11,7 @@ //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to //! `librustc_mir/interpret/intrinsics.rs` and add a -//! `#[rustc_const_unstable(feature = "foo2", issue = "01234")]` to the intrinsic. +//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index e1a040b2e0ea5..ff22b6b184e54 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -285,10 +285,10 @@ impl NonConstOp for Panic { pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = ccx.tcx.sess.struct_span_err( - span, - "pointers cannot be reliably compared during const eval.", - ); + let mut err = ccx + .tcx + .sess + .struct_span_err(span, "pointers cannot be reliably compared during const eval."); err.note( "see issue #53020 \ for more information", diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs index 083ebfdd4da3f..e238e13b8e2da 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,6 +1,6 @@ fn main() {} // unconst and bad, will thus error in miri -const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably compared +const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably // unconst and bad, will thus error in miri -const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably compared +const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably From 98e97a46e2201520f54082abe462728b0a770a6b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 20 Jun 2020 14:58:15 +0200 Subject: [PATCH 10/30] Address review comments --- src/libcore/ptr/const_ptr.rs | 4 +-- src/libcore/ptr/mut_ptr.rs | 4 +-- src/libcore/slice/mod.rs | 47 +++++++----------------------------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 0e2e6848416b6..e5ac81d8789ec 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -295,7 +295,7 @@ impl *const T { intrinsics::ptr_offset_from(self, origin) } - /// Returns whether two pointers are guaranteed equal. + /// Returns whether two pointers are guaranteed to be equal. /// /// At runtime this function behaves like `self == other`. /// However, in some contexts (e.g., compile-time evaluation), @@ -328,7 +328,7 @@ impl *const T { intrinsics::ptr_guaranteed_eq(self, other) } - /// Returns whether two pointers are guaranteed not equal. + /// Returns whether two pointers are guaranteed to be inequal. /// /// At runtime this function behaves like `self != other`. /// However, in some contexts (e.g., compile-time evaluation), diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 67ace1f72a0ab..b8ff5b0dc72cb 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -273,7 +273,7 @@ impl *mut T { if self.is_null() { None } else { Some(&mut *self) } } - /// Returns whether two pointers are guaranteed equal. + /// Returns whether two pointers are guaranteed to be equal. /// /// At runtime this function behaves like `self == other`. /// However, in some contexts (e.g., compile-time evaluation), @@ -306,7 +306,7 @@ impl *mut T { intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _) } - /// Returns whether two pointers are guaranteed not equal. + /// Returns whether two pointers are guaranteed to be inequal. /// /// At runtime this function behaves like `self != other`. /// However, in some contexts (e.g., compile-time evaluation), diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 12932b06d32d4..c69aafe687cf8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5946,8 +5946,7 @@ where } } -// Remove after boostrap bump -#[cfg(bootstrap)] +// Use an equal-pointer optimization when types are `Eq` impl SlicePartialEq for [A] where A: PartialEq + Eq, @@ -5957,47 +5956,14 @@ where return false; } + #[cfg(bootstrap)] if self.as_ptr() == other.as_ptr() { return true; } - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Remove after boostrap bump -#[cfg(bootstrap)] -impl SlicePartialEq for [A] -where - A: PartialEq + BytewiseEquality, -{ - fn equal(&self, other: &[A]) -> bool { - if self.len() != other.len() { - return false; - } - if self.as_ptr() == other.as_ptr() { - return true; - } - unsafe { - let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 - } - } -} - -// Use an equal-pointer optimization when types are `Eq` -#[cfg(not(bootstrap))] -impl SlicePartialEq for [A] -where - A: PartialEq + Eq, -{ - default fn equal(&self, other: &[A]) -> bool { - if self.len() != other.len() { - return false; - } - // While performance would suffer if `guaranteed_eq` just returned `false` // for all arguments, correctness and return value of this function are not affected. + #[cfg(not(bootstrap))] if self.as_ptr().guaranteed_eq(other.as_ptr()) { return true; } @@ -6007,7 +5973,6 @@ where } // Use memcmp for bytewise equality when the types allow -#[cfg(not(bootstrap))] impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality, @@ -6017,8 +5982,14 @@ where return false; } + #[cfg(bootstrap)] + if self.as_ptr() == other.as_ptr() { + return true; + } + // While performance would suffer if `guaranteed_eq` just returned `false` // for all arguments, correctness and return value of this function are not affected. + #[cfg(not(bootstrap))] if self.as_ptr().guaranteed_eq(other.as_ptr()) { return true; } From 935516803e2822da33479bcbc8d3dfb2833a8d49 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 20 Jun 2020 20:38:57 +0000 Subject: [PATCH 11/30] update tests --- .../ui/check-static-values-constraints.stderr | 4 ++- .../ui/consts/const-eval/const_let.stderr | 16 +++++++--- .../ui/consts/const-eval/issue-65394.stderr | 3 ++ src/test/ui/consts/const-eval/livedrop.rs | 20 ++++++++++++ src/test/ui/consts/const-eval/livedrop.stderr | 12 +++++++ .../control-flow/drop-fail.stock.stderr | 12 +++++++ .../consts/min_const_fn/min_const_fn.stderr | 12 +++++-- ...gate-unleash_the_miri_inside_of_you.stderr | 4 ++- .../unstable-const-fn-in-libcore.stderr | 6 ++++ src/test/ui/span/E0493.stderr | 4 ++- src/test/ui/static/static-drop-scope.stderr | 31 ++++++++++++++----- 11 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/consts/const-eval/livedrop.rs create mode 100644 src/test/ui/consts/const-eval/livedrop.stderr diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index 6b5a739899cac..b00affdca850a 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -5,7 +5,9 @@ LL | ..SafeStruct{field1: SafeEnum::Va | ___________________________________________^ LL | | LL | | field2: SafeEnum::Variant1}}; - | |________________________________________________________________________________^ statics cannot evaluate destructors + | | ^- value is dropped here + | |________________________________________________________________________________| + | statics cannot evaluate destructors error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:79:33 diff --git a/src/test/ui/consts/const-eval/const_let.stderr b/src/test/ui/consts/const-eval/const_let.stderr index 4753222a7c07d..47f39b703e460 100644 --- a/src/test/ui/consts/const-eval/const_let.stderr +++ b/src/test/ui/consts/const-eval/const_let.stderr @@ -2,25 +2,33 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/const_let.rs:16:32 | LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x }; - | ^^^^^ constants cannot evaluate destructors + | ^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/const_let.rs:20:33 | LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x }; - | ^^^^^ constants cannot evaluate destructors + | ^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/const_let.rs:24:21 | LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); }; - | ^^^^^ constants cannot evaluate destructors + | ^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/const_let.rs:28:22 | LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); }; - | ^^^^^ constants cannot evaluate destructors + | ^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index d85a1a1a3c32b..487f59099bd77 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -12,6 +12,9 @@ error[E0493]: destructors cannot be evaluated at compile-time | LL | let mut x = Vec::::new(); | ^^^^^ constants cannot evaluate destructors +... +LL | }; + | - value is dropped here error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/livedrop.rs b/src/test/ui/consts/const-eval/livedrop.rs new file mode 100644 index 0000000000000..f00d1c70659fd --- /dev/null +++ b/src/test/ui/consts/const-eval/livedrop.rs @@ -0,0 +1,20 @@ +#![feature(const_if_match)] +#![feature(const_loop)] + +const _: Option> = { + let mut never_returned = Some(Vec::new()); + let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time + + let mut i = 0; + loop { + always_returned = never_returned; + never_returned = None; + + i += 1; + if i == 10 { + break always_returned; + } + } +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/livedrop.stderr b/src/test/ui/consts/const-eval/livedrop.stderr new file mode 100644 index 0000000000000..b802d23d9a89c --- /dev/null +++ b/src/test/ui/consts/const-eval/livedrop.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/livedrop.rs:6:9 + | +LL | let mut always_returned = None; + | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors +... +LL | always_returned = never_returned; + | --------------- value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/control-flow/drop-fail.stock.stderr b/src/test/ui/consts/control-flow/drop-fail.stock.stderr index 77cded5c438b5..6a9ea91d20e1f 100644 --- a/src/test/ui/consts/control-flow/drop-fail.stock.stderr +++ b/src/test/ui/consts/control-flow/drop-fail.stock.stderr @@ -3,24 +3,36 @@ error[E0493]: destructors cannot be evaluated at compile-time | LL | let x = Some(Vec::new()); | ^ constants cannot evaluate destructors +... +LL | }; + | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/drop-fail.rs:23:9 | LL | let vec_tuple = (Vec::new(),); | ^^^^^^^^^ constants cannot evaluate destructors +... +LL | }; + | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/drop-fail.rs:31:9 | LL | let x: Result<_, Vec> = Ok(Vec::new()); | ^ constants cannot evaluate destructors +... +LL | }; + | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/drop-fail.rs:41:9 | LL | let mut tmp = None; | ^^^^^^^ constants cannot evaluate destructors +... +LL | }; + | - value is dropped here error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 512b343011b40..4b0401ebf9dba 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:37:25 | LL | const fn into_inner(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors + | ^^^^ - value is dropped here + | | + | constant functions cannot evaluate destructors error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:39:36 @@ -17,7 +19,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:44:28 | LL | const fn into_inner_lt(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors + | ^^^^ - value is dropped here + | | + | constant functions cannot evaluate destructors error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:46:42 @@ -32,7 +36,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/min_const_fn.rs:51:27 | LL | const fn into_inner_s(self) -> T { self.0 } - | ^^^^ constant functions cannot evaluate destructors + | ^^^^ - value is dropped here + | | + | constant functions cannot evaluate destructors error[E0723]: mutable references in const fn are unstable --> $DIR/min_const_fn.rs:53:38 diff --git a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr index 37016664ac58f..0b6cb2fab46f1 100644 --- a/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr +++ b/src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr @@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20 | LL | const F: u32 = (U::X, 42).1; - | ^^^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error: aborting due to previous error diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index a8455cefd01cf..928605356a16e 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -9,12 +9,18 @@ error[E0493]: destructors cannot be evaluated at compile-time | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:47 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here error: aborting due to 3 previous errors diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr index d05e89e257f45..29d1b00094321 100644 --- a/src/test/ui/span/E0493.stderr +++ b/src/test/ui/span/E0493.stderr @@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/E0493.rs:17:17 | LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error: aborting due to previous error diff --git a/src/test/ui/static/static-drop-scope.stderr b/src/test/ui/static/static-drop-scope.stderr index bc08f33f82093..ed81734f6ebd7 100644 --- a/src/test/ui/static/static-drop-scope.stderr +++ b/src/test/ui/static/static-drop-scope.stderr @@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:9:60 | LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^ statics cannot evaluate destructors + | ^^^^^^^^- value is dropped here + | | + | statics cannot evaluate destructors error[E0716]: temporary value dropped while borrowed --> $DIR/static-drop-scope.rs:9:60 @@ -18,7 +20,9 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:13:59 | LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); - | ^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^- value is dropped here + | | + | constants cannot evaluate destructors error[E0716]: temporary value dropped while borrowed --> $DIR/static-drop-scope.rs:13:59 @@ -34,37 +38,50 @@ error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:17:28 | LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1; - | ^^^^^^^^^^^^^ statics cannot evaluate destructors + | ^^^^^^^^^^^^^ - value is dropped here + | | + | statics cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:20:27 | LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; - | ^^^^^^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:23:24 | LL | const fn const_drop(_: T) {} - | ^ constant functions cannot evaluate destructors + | ^ - value is dropped here + | | + | constant functions cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:27:5 | LL | (x, ()).1 | ^^^^^^^ constant functions cannot evaluate destructors +LL | +LL | } + | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:31:34 | LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; - | ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^^^^^^^^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:36:43 | LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; - | ^^^^^^^^^^^ constants cannot evaluate destructors + | ^^^^^^^^^^^ - value is dropped here + | | + | constants cannot evaluate destructors error: aborting due to 10 previous errors From a63eb3c67865ef0ae881642da7178a98e51a5a36 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Sat, 20 Jun 2020 17:02:18 -0700 Subject: [PATCH 12/30] Clarify --extern documentation. Fixes #64731, #73531. See also #64402#issuecomment-530852886 --- src/doc/rustc/src/command-line-arguments.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7a7838d965bc7..30b18eb56a125 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -273,10 +273,18 @@ This flag, when combined with other flags, makes them produce extra output. This flag allows you to pass the name and location for an external crate of a direct dependency. Indirect dependencies (dependencies of dependencies) are located using the [`-L` flag](#option-l-search-path). The given crate name is -added to the [extern prelude], which is the same as specifying `extern crate` -within the root module. The given crate name does not need to match the name +added to the [extern prelude], similar to specifying `extern crate` within the +root module. The given crate name does not need to match the name the library was built with. +Specifying `--extern` has one behavior difference from `extern crate`: +`--extern` merely makes the crate a _candidate_ for being linked; it does not +actually link it unless it's actively used. In rare occasions you may wish +to ensure a crate is linked even if you don't actively use it from your +code: for example, if it changes the global allocator or if it contains +`#[no_mangle]` symbols for use by other programming languages. In such +cases you'll need to use `extern crate`. + This flag may be specified multiple times. This flag takes an argument with either of the following formats: From 63740548aa8887c92d8976ccf478cfb0c44611a5 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Sat, 20 Jun 2020 22:53:51 -0400 Subject: [PATCH 13/30] Fix typos in doc comments This commit fixes typos in the doc comments of 'librustc_mir/monomorphize/collector.rs' --- src/librustc_mir/monomorphize/collector.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 36f3947d83017..448d8cdd6c6f6 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1,7 +1,7 @@ //! Mono Item Collection //! ==================== //! -//! This module is responsible for discovering all items that will contribute to +//! This module is responsible for discovering all items that will contribute //! to code generation of the crate. The important part here is that it not only //! needs to find syntax-level items (functions, structs, etc) but also all //! their monomorphized instantiations. Every non-generic, non-const function @@ -79,7 +79,7 @@ //! function or method call (represented by a CALL terminator in MIR). But //! calls are not the only thing that might introduce a reference between two //! function mono items, and as we will see below, they are just a -//! specialized of the form described next, and consequently will don't get any +//! specialized of the form described next, and consequently will not get any //! special treatment in the algorithm. //! //! #### Taking a reference to a function or method @@ -158,7 +158,7 @@ //! - Eager mode is meant to be used in conjunction with incremental compilation //! where a stable set of mono items is more important than a minimal //! one. Thus, eager mode will instantiate drop-glue for every drop-able type -//! in the crate, even of no drop call for that type exists (yet). It will +//! in the crate, even if no drop call for that type exists (yet). It will //! also instantiate default implementations of trait methods, something that //! otherwise is only done on demand. //! From e465b227d15fec8f16863ba8e77191ceb5c8670b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 21 Jun 2020 13:17:05 +0200 Subject: [PATCH 14/30] `icmp` can handle raw pointers just fine, there's no need to cast to int. --- src/librustc_codegen_llvm/intrinsic.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 78c29588e2e1b..0a8525f06fa3d 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -734,8 +734,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => { let a = args[0].immediate(); let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); if name == "ptr_guaranteed_eq" { self.icmp(IntPredicate::IntEQ, a, b) } else { From 893077ca76eeb1ad35608872d534478d68c953c9 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Sun, 21 Jun 2020 11:43:30 -0400 Subject: [PATCH 15/30] Update src/librustc_mir/monomorphize/collector.rs typo fix Co-authored-by: Jonas Schievink --- src/librustc_mir/monomorphize/collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 448d8cdd6c6f6..e51d9ba9c021d 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -79,7 +79,7 @@ //! function or method call (represented by a CALL terminator in MIR). But //! calls are not the only thing that might introduce a reference between two //! function mono items, and as we will see below, they are just a -//! specialized of the form described next, and consequently will not get any +//! specialization of the form described next, and consequently will not get any //! special treatment in the algorithm. //! //! #### Taking a reference to a function or method From b60ec47a0694b6eb10bdafc2aa28f877473f61d5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 21 Jun 2020 20:21:17 +0100 Subject: [PATCH 16/30] bootstrap: no `config.toml` exists regression This commit fixes a regression introduced in #73317 where an oversight meant that `config.toml` was assumed to exist. Signed-off-by: David Wood --- src/bootstrap/bootstrap.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 969d16d11e81b..82a755c7892b1 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -893,15 +893,18 @@ def bootstrap(help_triggered): build.verbose = args.verbose build.clean = args.clean - try: - toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config or 'config.toml' + # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it + # exists). + toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config + if not toml_path and os.path.exists('config.toml'): + toml_path = 'config.toml' + + if toml_path: if not os.path.exists(toml_path): toml_path = os.path.join(build.rust_root, toml_path) with open(toml_path) as config: build.config_toml = config.read() - except (OSError, IOError): - pass config_verbose = build.get_toml('verbose', 'build') if config_verbose is not None: @@ -947,11 +950,12 @@ def bootstrap(help_triggered): env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable - env["BOOTSTRAP_CONFIG"] = toml_path env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' env["CARGO"] = build.cargo() env["RUSTC"] = build.rustc() + if toml_path: + env["BOOTSTRAP_CONFIG"] = toml_path if build.rustfmt(): env["RUSTFMT"] = build.rustfmt() run(args, env=env, verbose=build.verbose) From bcc0a9c8eba0c4eaaafb7983b1b367a926ca8948 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 18 May 2020 09:43:36 +0000 Subject: [PATCH 17/30] modify leak-check to track only outgoing edges from placeholders Also, update the affected tests. This seems strictly better but it is actually more permissive than I initially intended. In particular it accepts this ``` forall<'a, 'b> { exists<'intersection> { 'a: 'intersection, 'b: 'intersection, } } ``` and I'm not sure I want to accept that. It implies that we have a `'empty` in the new universe intoduced by the `forall`. --- .../infer/region_constraints/leak_check.rs | 21 ++++++-- .../expect-fn-supply-fn.rs | 6 +-- .../expect-fn-supply-fn.stderr | 51 +++++++------------ .../hr-subtype.bound_a_b_vs_bound_a.stderr | 23 ++++----- .../hr-subtype.bound_a_vs_bound_a.stderr | 4 +- .../hr-subtype.bound_a_vs_bound_b.stderr | 4 +- .../hr-subtype.bound_a_vs_free_x.stderr | 2 +- ...-subtype.bound_co_a_b_vs_bound_co_a.stderr | 23 ++++----- ...ubtype.bound_co_a_co_b_ret_contra_a.stderr | 23 ++++----- ...hr-subtype.bound_co_a_vs_bound_co_b.stderr | 4 +- ...pe.bound_contra_a_contra_b_ret_co_a.stderr | 23 ++++----- ...-subtype.bound_inv_a_vs_bound_inv_b.stderr | 4 +- .../hr-subtype.free_x_vs_free_x.stderr | 4 +- src/test/ui/hr-subtype/hr-subtype.rs | 8 +-- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 4 +- .../hrtb-exists-forall-trait-contravariant.rs | 2 +- ...b-exists-forall-trait-contravariant.stderr | 18 +++---- ...igher-ranker-supertraits-transitive.stderr | 19 +++---- src/test/ui/hrtb/hrtb-just-for-static.stderr | 20 ++++---- src/test/ui/hrtb/issue-46989.rs | 2 +- src/test/ui/hrtb/issue-46989.stderr | 19 +++---- src/test/ui/issues/issue-57362-1.rs | 2 +- src/test/ui/issues/issue-57362-1.stderr | 21 ++++---- src/test/ui/issues/issue-57362-2.rs | 4 +- src/test/ui/issues/issue-57362-2.stderr | 39 ++++++++++---- src/test/ui/lub-glb/old-lub-glb-hr.rs | 35 +++++++++++-- src/test/ui/lub-glb/old-lub-glb-hr.stderr | 10 ++-- ...ons-fn-subtyping-return-static-fail.stderr | 4 +- src/test/ui/where-clauses/where-for-self-2.rs | 2 +- .../ui/where-clauses/where-for-self-2.stderr | 19 ++++--- 30 files changed, 219 insertions(+), 201 deletions(-) diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 91c39a0e78ffb..111a7b997a486 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -42,10 +42,23 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,), }; - // Find all regions that are related to this placeholder - // in some way. This means any region that either outlives - // or is outlived by a placeholder. - let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); + // Find all regions that this placeholder `!p` must outlive -- i.e., + // any region `r` where `!p: r` must hold. It is an error if any + // such region `r` is another placeholder or in a universe that + // can't see the placeholder. (This is actually incorrect, because + // we don't take into account the possibility of bounds in + // environment that tell us that the placeholder may be related to + // other regions). + // + // Note that we *don't* look for cases like `r: !p`. This is + // because: + // + // * If `r` is some other placeholder `!p1`, then we'll find the + // error when we search the regions that `!p1` must outlive. + // * If `r` is a variable in some outer universe, then it can + // potentially be assigned to `'static`, so this relation could + // hold. + let mut taint_set = TaintSet::new(TaintDirections::outgoing(), placeholder_region); taint_set.fixed_point( tcx, self.undo_log.region_constraints(), diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs index a4e43da91baf8..6977fd47a2e85 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs @@ -28,14 +28,14 @@ fn expect_free_supply_bound() { // Here, we are given a function whose region is bound at closure level, // but we expect one bound in the argument. Error results. with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - //~^ ERROR type mismatch + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { // Here, we are given a `fn(&u32)` but we expect a `fn(&'x // u32)`. In principle, this could be ok, but we demand equality. with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - //~^ ERROR type mismatch + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_closure() { @@ -44,7 +44,7 @@ fn expect_bound_supply_free_from_closure() { // the argument level. type Foo<'a> = fn(&'a u32); with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - //~^ ERROR type mismatch + //~^ ERROR mismatched types }); } diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index fae41c4114abc..8a183bb704b4d 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -36,46 +36,33 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:30:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:30:52 | -LL | fn with_closure_expecting_fn_with_free_region(_: F) - | ------------------------------------------ required by a bound in this -LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) - | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` -... LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `fn(fn(&'a u32), &i32) -> _` + | ^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `fn(&u32)` + found fn pointer `for<'r> fn(&'r u32)` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:37:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:37:53 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` -... LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^^^^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'r> fn(&'r u32)` + found fn pointer `fn(&'x u32)` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:46:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:46:53 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` -... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'r> fn(&'r u32)` + found fn pointer `fn(&u32)` error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0631. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index 45f53d4fe99db..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), -LL | | for<'a> fn(&'a u32, &'a u32)) } - | |__________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(&'a u32, &'b u32)>` - found enum `std::option::Option fn(&'a u32, &'a u32)>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 6aba6466fada5..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 6aba6466fada5..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index c3e4f6d2ed0c1..b3e3f5dc401cf 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index 4d7b86027f564..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), -LL | | for<'a> fn(Co<'a>, Co<'a>)) } - | |______________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>)>` - found enum `std::option::Option fn(Co<'a>, Co<'a>)>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index 7f0a4197dd7fe..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, -LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } - | |______________________________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>) -> Contra<'a>>` - found enum `std::option::Option fn(Co<'a>, Co<'a>) -> Contra<'a>>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 6aba6466fada5..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index c12e543a44e79..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:96:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, -LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } - | |______________________________________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Contra<'a>, Contra<'b>) -> Co<'a>>` - found enum `std::option::Option fn(Contra<'a>, Contra<'a>) -> Co<'a>>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 6aba6466fada5..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 6aba6466fada5..c4e838e6887b5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:96:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs index b31f198bd97bf..995ec64d53b83 100644 --- a/src/test/ui/hr-subtype/hr-subtype.rs +++ b/src/test/ui/hr-subtype/hr-subtype.rs @@ -42,10 +42,6 @@ macro_rules! check { //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR - //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types - //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR - //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR - //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR } } } @@ -103,4 +99,8 @@ fn main() { //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error] //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error] //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error] +//[bound_a_b_vs_bound_a]~^^^^^^ ERROR fatal error triggered by #[rustc_error] +//[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR fatal error triggered by #[rustc_error] +//[bound_co_a_co_b_ret_contra_a]~^^^^^^^^ ERROR fatal error triggered by #[rustc_error] +//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR fatal error triggered by #[rustc_error] } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 328e98657effb..9914783d9767d 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/hrtb-exists-forall-fn.rs:17:34 | LL | let _: for<'b> fn(&'b u32) = foo(); - | ------------------- ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b - | | - | expected due to this + | ^^^^^ one type is more general than the other | = note: expected fn pointer `for<'b> fn(&'b u32)` found fn pointer `fn(&u32)` diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs index 4c1d4d28a09b0..921061916fc95 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs @@ -32,5 +32,5 @@ fn main() { // NB. *However*, the reinstated leak-check gives an error here. foo::<()>(); - //~^ ERROR not satisfied + //~^ ERROR implementation of `Trait` is not general enough } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index 7a7285d3d76e0..fe8209d054c8a 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -1,18 +1,14 @@ -error[E0277]: the trait bound `(): Trait fn(&'b u32)>` is not satisfied - --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11 +error: implementation of `Trait` is not general enough + --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | -LL | fn foo() - | --- required by a bound in this -LL | where -LL | T: Trait fn(&'b u32)>, - | -------------------------- required by this bound in `foo` +LL | trait Trait {} + | ----------------- trait `Trait` defined here ... LL | foo::<()>(); - | ^^ the trait `Trait fn(&'b u32)>` is not implemented for `()` + | ^^^^^^^^^ implementation of `Trait` is not general enough | - = help: the following implementations were found: - <() as Trait> + = note: `()` must implement `Trait fn(&'b u32)>` + = note: ...but `()` actually implements `Trait`, for some specific lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index 87a13889298df..ebb3abf184856 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,19 +1,12 @@ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this -LL | where B : for<'ccx> Bar<'ccx> - | ------------------- required by this bound in `want_bar_for_any_ccx` -... LL | want_bar_for_any_ccx(b); - | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | -help: consider further restricting this bound - | -LL | where B : Qux + for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^^^ + = note: expected type `for<'ccx> Bar<'ccx>` + found type `Bar<'static>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 4fa404624775b..bf7373059a074 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied - --> $DIR/hrtb-just-for-static.rs:24:17 +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | fn want_hrtb() - | --------- required by a bound in this -LL | where T : for<'a> Foo<&'a isize> - | ---------------------- required by this bound in `want_hrtb` +LL | / trait Foo { +LL | | fn foo(&self, x: X) { } +LL | | } + | |_- trait `Foo` defined here ... -LL | want_hrtb::() - | ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` +LL | want_hrtb::() + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - > + = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... + = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:30:17 diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs index 2c85905545807..eb6549099fe6a 100644 --- a/src/test/ui/hrtb/issue-46989.rs +++ b/src/test/ui/hrtb/issue-46989.rs @@ -38,5 +38,5 @@ fn assert_foo() {} fn main() { assert_foo::(); - //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied + //~^ ERROR implementation of `Foo` is not general enough } diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr index 0a7382c4dd818..0865aa4224b97 100644 --- a/src/test/ui/hrtb/issue-46989.stderr +++ b/src/test/ui/hrtb/issue-46989.stderr @@ -1,15 +1,16 @@ -error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied - --> $DIR/issue-46989.rs:40:18 +error: implementation of `Foo` is not general enough + --> $DIR/issue-46989.rs:40:5 | -LL | fn assert_foo() {} - | --- required by this bound in `assert_foo` +LL | / trait Foo { +LL | | +LL | | } + | |_- trait `Foo` defined here ... -LL | assert_foo::(); - | ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)` +LL | assert_foo::(); + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - + = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)` + = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-57362-1.rs b/src/test/ui/issues/issue-57362-1.rs index 1fa417fe98ab7..3ba82300fabea 100644 --- a/src/test/ui/issues/issue-57362-1.rs +++ b/src/test/ui/issues/issue-57362-1.rs @@ -17,7 +17,7 @@ impl Trait for fn(&T) { fn f() { let a: fn(_) = |_: &u8| {}; - a.f(); //~ ERROR no method named `f` + a.f(); //~ ERROR implementation of `Trait` is not general enough } fn main() {} diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr index 5c611cd43d3cc..24408420b1373 100644 --- a/src/test/ui/issues/issue-57362-1.stderr +++ b/src/test/ui/issues/issue-57362-1.stderr @@ -1,17 +1,16 @@ -error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current scope +error: implementation of `Trait` is not general enough --> $DIR/issue-57362-1.rs:20:7 | -LL | a.f(); - | ^ method not found in `fn(&u8)` +LL | / trait Trait { +LL | | fn f(self); +LL | | } + | |_- trait `Trait` defined here +... +LL | a.f(); + | ^ implementation of `Trait` is not general enough | - = note: `a` is a function, perhaps you wish to call it - = help: items from traits can only be used if the trait is implemented and in scope -note: `Trait` defines an item `f`, perhaps you need to implement it - --> $DIR/issue-57362-1.rs:8:1 - | -LL | trait Trait { - | ^^^^^^^^^^^ + = note: `Trait` would have to be implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`... + = note: ...but `Trait` is actually implemented for the type `for<'r> fn(&'r u8)` error: aborting due to previous error -For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-57362-2.rs b/src/test/ui/issues/issue-57362-2.rs index 870d7f28ba953..7b6594abc9647 100644 --- a/src/test/ui/issues/issue-57362-2.rs +++ b/src/test/ui/issues/issue-57362-2.rs @@ -19,7 +19,9 @@ impl<'a> X for fn(&'a ()) { } fn g() { - let x = ::make_g(); //~ ERROR no function or associated item + let x = ::make_g(); + //~^ ERROR implementation of `X` is not general enough + //~| ERROR implementation of `X` is not general enough } fn main() {} diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index 2edc009746455..dfd48ec22275b 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -1,16 +1,33 @@ -error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'r> fn(&'r ())` in the current scope - --> $DIR/issue-57362-2.rs:22:25 +error: implementation of `X` is not general enough + --> $DIR/issue-57362-2.rs:22:13 | -LL | let x = ::make_g(); - | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` +LL | / trait X { +LL | | type G; +LL | | fn make_g() -> Self::G; +LL | | } + | |_- trait `X` defined here +... +LL | let x = ::make_g(); + | ^^^^^^^^^^^^^^^^^^ implementation of `X` is not general enough | - = help: items from traits can only be used if the trait is implemented and in scope -note: `X` defines an item `make_g`, perhaps you need to implement it - --> $DIR/issue-57362-2.rs:8:1 + = note: `X` would have to be implemented for the type `for<'r> fn(&'r ())` + = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` + +error: implementation of `X` is not general enough + --> $DIR/issue-57362-2.rs:22:13 + | +LL | / trait X { +LL | | type G; +LL | | fn make_g() -> Self::G; + | | ----------------------- due to a where-clause on `X::make_g`... +LL | | } + | |_- trait `X` defined here +... +LL | let x = ::make_g(); + | ^^^^^^^^^^^^^^^^^^ doesn't satisfy where-clause | -LL | trait X { - | ^^^^^^^ + = note: ...`X` would have to be implemented for the type `for<'r> fn(&'r ())` + = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs index bc7b787cd65ac..5e24a99bcc331 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.rs +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -3,21 +3,21 @@ // error. However, now that we handle subtyping correctly, we no // longer get an error, because we recognize these two types as // equivalent! -// -// Whoops -- now that we reinstituted the leak-check, we get an error -// again. fn foo( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { + // The two types above are actually equivalent. With the older + // leak check, though, we didn't consider them as equivalent, and + // hence we gave errors. But now we've fixed that. let z = match 22 { 0 => x, - _ => y, //~ ERROR `match` arms have incompatible types + _ => y, }; } -fn bar( +fn foo_cast( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { @@ -28,5 +28,30 @@ fn bar( }; } +fn bar( + x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, + y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, +) { + // The two types above are not equivalent. With the older LUB/GLB + // algorithm, this may have worked (I don't remember), but now it + // doesn't because we require equality. + let z = match 22 { + 0 => x, + _ => y, //~ ERROR `match` arms have incompatible types + }; +} + +fn bar_cast( + x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, + y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, +) { + // But we can *upcast* explicitly the type of `x` and figure + // things out: + let z = match 22 { + 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, + _ => y, + }; +} + fn main() { } diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr index 6d5d51174699f..d242fb7789aa1 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -1,17 +1,17 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/old-lub-glb-hr.rs:16:14 + --> $DIR/old-lub-glb-hr.rs:40:14 | LL | let z = match 22 { | _____________- LL | | 0 => x, - | | - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)` + | | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` LL | | _ => y, - | | ^ expected bound lifetime parameter, found concrete lifetime + | | ^ expected bound lifetime parameter 'a, found concrete lifetime LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)` - found fn pointer `for<'a> fn(&'a u8, &'a u8)` + = note: expected type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` error: aborting due to previous error diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 27704b3e0a8c7..7848f770a70cf 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -11,10 +11,10 @@ error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | LL | want_G(baz); - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx + | ^^^ one type is more general than the other | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S` - found fn item `for<'r> fn(&'r S) -> &'r S {baz}` + found fn pointer `for<'r> fn(&'r S) -> &'r S` error: aborting due to 2 previous errors diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs index 31174fd4cf163..0ce38e69f6b0f 100644 --- a/src/test/ui/where-clauses/where-for-self-2.rs +++ b/src/test/ui/where-clauses/where-for-self-2.rs @@ -18,5 +18,5 @@ fn foo(x: &T) {} fn main() { - foo(&X); //~ ERROR trait bound + foo(&X); //~ ERROR implementation of `Bar` is not general enough } diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 9976243b200dc..b3cadf5b1b078 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,17 +1,16 @@ -error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied +error: implementation of `Bar` is not general enough --> $DIR/where-for-self-2.rs:21:5 | -LL | fn foo(x: &T) - | --- required by a bound in this -LL | where for<'a> &'a T: Bar - | --- required by this bound in `foo` +LL | / trait Bar { +LL | | fn bar(&self); +LL | | } + | |_- trait `Bar` defined here ... -LL | foo(&X); - | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` +LL | foo(&X); + | ^^^ implementation of `Bar` is not general enough | - = help: the following implementations were found: - <&'static u32 as Bar> + = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. From 4199b3ae26007eb9c871b57f56057da586bbd1db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 18 May 2020 21:43:11 +0000 Subject: [PATCH 18/30] Revert "modify leak-check to track only outgoing edges from placeholders" This reverts commit 2e01db4b396a1e161f7a73933fff34bc9421dba0. --- .../infer/region_constraints/leak_check.rs | 21 ++------ .../expect-fn-supply-fn.rs | 6 +-- .../expect-fn-supply-fn.stderr | 51 ++++++++++++------- .../hr-subtype.bound_a_b_vs_bound_a.stderr | 23 +++++---- .../hr-subtype.bound_a_vs_bound_a.stderr | 4 +- .../hr-subtype.bound_a_vs_bound_b.stderr | 4 +- .../hr-subtype.bound_a_vs_free_x.stderr | 2 +- ...-subtype.bound_co_a_b_vs_bound_co_a.stderr | 23 +++++---- ...ubtype.bound_co_a_co_b_ret_contra_a.stderr | 23 +++++---- ...hr-subtype.bound_co_a_vs_bound_co_b.stderr | 4 +- ...pe.bound_contra_a_contra_b_ret_co_a.stderr | 23 +++++---- ...-subtype.bound_inv_a_vs_bound_inv_b.stderr | 4 +- .../hr-subtype.free_x_vs_free_x.stderr | 4 +- src/test/ui/hr-subtype/hr-subtype.rs | 8 +-- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 4 +- .../hrtb-exists-forall-trait-contravariant.rs | 2 +- ...b-exists-forall-trait-contravariant.stderr | 18 ++++--- ...igher-ranker-supertraits-transitive.stderr | 19 ++++--- src/test/ui/hrtb/hrtb-just-for-static.stderr | 20 ++++---- src/test/ui/hrtb/issue-46989.rs | 2 +- src/test/ui/hrtb/issue-46989.stderr | 19 ++++--- src/test/ui/issues/issue-57362-1.rs | 2 +- src/test/ui/issues/issue-57362-1.stderr | 21 ++++---- src/test/ui/issues/issue-57362-2.rs | 4 +- src/test/ui/issues/issue-57362-2.stderr | 39 ++++---------- src/test/ui/lub-glb/old-lub-glb-hr.rs | 35 ++----------- src/test/ui/lub-glb/old-lub-glb-hr.stderr | 10 ++-- ...ons-fn-subtyping-return-static-fail.stderr | 4 +- src/test/ui/where-clauses/where-for-self-2.rs | 2 +- .../ui/where-clauses/where-for-self-2.stderr | 19 +++---- 30 files changed, 201 insertions(+), 219 deletions(-) diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 111a7b997a486..91c39a0e78ffb 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -42,23 +42,10 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,), }; - // Find all regions that this placeholder `!p` must outlive -- i.e., - // any region `r` where `!p: r` must hold. It is an error if any - // such region `r` is another placeholder or in a universe that - // can't see the placeholder. (This is actually incorrect, because - // we don't take into account the possibility of bounds in - // environment that tell us that the placeholder may be related to - // other regions). - // - // Note that we *don't* look for cases like `r: !p`. This is - // because: - // - // * If `r` is some other placeholder `!p1`, then we'll find the - // error when we search the regions that `!p1` must outlive. - // * If `r` is a variable in some outer universe, then it can - // potentially be assigned to `'static`, so this relation could - // hold. - let mut taint_set = TaintSet::new(TaintDirections::outgoing(), placeholder_region); + // Find all regions that are related to this placeholder + // in some way. This means any region that either outlives + // or is outlived by a placeholder. + let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); taint_set.fixed_point( tcx, self.undo_log.region_constraints(), diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs index 6977fd47a2e85..a4e43da91baf8 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs @@ -28,14 +28,14 @@ fn expect_free_supply_bound() { // Here, we are given a function whose region is bound at closure level, // but we expect one bound in the argument. Error results. with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - //~^ ERROR mismatched types + //~^ ERROR type mismatch } fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { // Here, we are given a `fn(&u32)` but we expect a `fn(&'x // u32)`. In principle, this could be ok, but we demand equality. with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - //~^ ERROR mismatched types + //~^ ERROR type mismatch } fn expect_bound_supply_free_from_closure() { @@ -44,7 +44,7 @@ fn expect_bound_supply_free_from_closure() { // the argument level. type Foo<'a> = fn(&'a u32); with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - //~^ ERROR mismatched types + //~^ ERROR type mismatch }); } diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index 8a183bb704b4d..fae41c4114abc 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -36,33 +36,46 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/expect-fn-supply-fn.rs:30:52 +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:30:5 | +LL | fn with_closure_expecting_fn_with_free_region(_: F) + | ------------------------------------------ required by a bound in this +LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) + | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` +... LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^ one type is more general than the other - | - = note: expected fn pointer `fn(&u32)` - found fn pointer `for<'r> fn(&'r u32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` + | | + | expected signature of `fn(fn(&'a u32), &i32) -> _` -error[E0308]: mismatched types - --> $DIR/expect-fn-supply-fn.rs:37:53 +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:37:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- required by a bound in this +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^ one type is more general than the other - | - = note: expected fn pointer `for<'r> fn(&'r u32)` - found fn pointer `fn(&'x u32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` -error[E0308]: mismatched types - --> $DIR/expect-fn-supply-fn.rs:46:53 +error[E0631]: type mismatch in closure arguments + --> $DIR/expect-fn-supply-fn.rs:46:5 | +LL | fn with_closure_expecting_fn_with_bound_region(_: F) + | ------------------------------------------- required by a bound in this +LL | where F: FnOnce(fn(&u32), &i32) + | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^ one type is more general than the other - | - = note: expected fn pointer `for<'r> fn(&'r u32)` - found fn pointer `fn(&u32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0631. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index c4e838e6887b5..45f53d4fe99db 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,14 +1,17 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 +error[E0308]: mismatched types + --> $DIR/hr-subtype.rs:39:26 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a +... +LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), +LL | | for<'a> fn(&'a u32, &'a u32)) } + | |__________________________________________________________________- in this macro invocation + | + = note: expected enum `std::option::Option fn(&'a u32, &'b u32)>` + found enum `std::option::Option fn(&'a u32, &'a u32)>` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index c4e838e6887b5..6aba6466fada5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 + --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { LL | | LL | | LL | | -... | +LL | | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index c4e838e6887b5..6aba6466fada5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 + --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { LL | | LL | | LL | | -... | +LL | | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index b3e3f5dc401cf..c3e4f6d2ed0c1 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ one type is more general than the other + | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index c4e838e6887b5..4d7b86027f564 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,14 +1,17 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 +error[E0308]: mismatched types + --> $DIR/hr-subtype.rs:39:26 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a +... +LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), +LL | | for<'a> fn(Co<'a>, Co<'a>)) } + | |______________________________________________________________________- in this macro invocation + | + = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>)>` + found enum `std::option::Option fn(Co<'a>, Co<'a>)>` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index c4e838e6887b5..7f0a4197dd7fe 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,14 +1,17 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 +error[E0308]: mismatched types + --> $DIR/hr-subtype.rs:39:26 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a +... +LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, +LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } + | |______________________________________________________________________________________- in this macro invocation + | + = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>) -> Contra<'a>>` + found enum `std::option::Option fn(Co<'a>, Co<'a>) -> Contra<'a>>` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index c4e838e6887b5..6aba6466fada5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 + --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { LL | | LL | | LL | | -... | +LL | | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index c4e838e6887b5..c12e543a44e79 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,14 +1,17 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 +error[E0308]: mismatched types + --> $DIR/hr-subtype.rs:39:26 | -LL | / fn main() { -LL | | -LL | | -LL | | -... | -LL | | -LL | | } - | |_^ +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a +... +LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, +LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } + | |______________________________________________________________________________________________- in this macro invocation + | + = note: expected enum `std::option::Option fn(Contra<'a>, Contra<'b>) -> Co<'a>>` + found enum `std::option::Option fn(Contra<'a>, Contra<'a>) -> Co<'a>>` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index c4e838e6887b5..6aba6466fada5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 + --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { LL | | LL | | LL | | -... | +LL | | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index c4e838e6887b5..6aba6466fada5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:96:1 + --> $DIR/hr-subtype.rs:100:1 | LL | / fn main() { LL | | LL | | LL | | -... | +LL | | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs index 995ec64d53b83..b31f198bd97bf 100644 --- a/src/test/ui/hr-subtype/hr-subtype.rs +++ b/src/test/ui/hr-subtype/hr-subtype.rs @@ -42,6 +42,10 @@ macro_rules! check { //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR + //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types + //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR + //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR + //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR } } } @@ -99,8 +103,4 @@ fn main() { //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error] //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error] //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error] -//[bound_a_b_vs_bound_a]~^^^^^^ ERROR fatal error triggered by #[rustc_error] -//[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR fatal error triggered by #[rustc_error] -//[bound_co_a_co_b_ret_contra_a]~^^^^^^^^ ERROR fatal error triggered by #[rustc_error] -//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR fatal error triggered by #[rustc_error] } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 9914783d9767d..328e98657effb 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/hrtb-exists-forall-fn.rs:17:34 | LL | let _: for<'b> fn(&'b u32) = foo(); - | ^^^^^ one type is more general than the other + | ------------------- ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b + | | + | expected due to this | = note: expected fn pointer `for<'b> fn(&'b u32)` found fn pointer `fn(&u32)` diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs index 921061916fc95..4c1d4d28a09b0 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs @@ -32,5 +32,5 @@ fn main() { // NB. *However*, the reinstated leak-check gives an error here. foo::<()>(); - //~^ ERROR implementation of `Trait` is not general enough + //~^ ERROR not satisfied } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index fe8209d054c8a..7a7285d3d76e0 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -1,14 +1,18 @@ -error: implementation of `Trait` is not general enough - --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 +error[E0277]: the trait bound `(): Trait fn(&'b u32)>` is not satisfied + --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11 | -LL | trait Trait {} - | ----------------- trait `Trait` defined here +LL | fn foo() + | --- required by a bound in this +LL | where +LL | T: Trait fn(&'b u32)>, + | -------------------------- required by this bound in `foo` ... LL | foo::<()>(); - | ^^^^^^^^^ implementation of `Trait` is not general enough + | ^^ the trait `Trait fn(&'b u32)>` is not implemented for `()` | - = note: `()` must implement `Trait fn(&'b u32)>` - = note: ...but `()` actually implements `Trait`, for some specific lifetime `'0` + = help: the following implementations were found: + <() as Trait> error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index ebb3abf184856..87a13889298df 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,12 +1,19 @@ -error[E0308]: mismatched types - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 +error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied + --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 | +LL | fn want_bar_for_any_ccx(b: &B) + | -------------------- required by a bound in this +LL | where B : for<'ccx> Bar<'ccx> + | ------------------- required by this bound in `want_bar_for_any_ccx` +... LL | want_bar_for_any_ccx(b); - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` | - = note: expected type `for<'ccx> Bar<'ccx>` - found type `Bar<'static>` +help: consider further restricting this bound + | +LL | where B : Qux + for<'ccx> Bar<'ccx> + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index bf7373059a074..4fa404624775b 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,16 +1,16 @@ -error: implementation of `Foo` is not general enough - --> $DIR/hrtb-just-for-static.rs:24:5 +error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied + --> $DIR/hrtb-just-for-static.rs:24:17 | -LL | / trait Foo { -LL | | fn foo(&self, x: X) { } -LL | | } - | |_- trait `Foo` defined here +LL | fn want_hrtb() + | --------- required by a bound in this +LL | where T : for<'a> Foo<&'a isize> + | ---------------------- required by this bound in `want_hrtb` ... -LL | want_hrtb::() - | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | want_hrtb::() + | ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` | - = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... - = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` + = help: the following implementations were found: + > error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:30:17 diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs index eb6549099fe6a..2c85905545807 100644 --- a/src/test/ui/hrtb/issue-46989.rs +++ b/src/test/ui/hrtb/issue-46989.rs @@ -38,5 +38,5 @@ fn assert_foo() {} fn main() { assert_foo::(); - //~^ ERROR implementation of `Foo` is not general enough + //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied } diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr index 0865aa4224b97..0a7382c4dd818 100644 --- a/src/test/ui/hrtb/issue-46989.stderr +++ b/src/test/ui/hrtb/issue-46989.stderr @@ -1,16 +1,15 @@ -error: implementation of `Foo` is not general enough - --> $DIR/issue-46989.rs:40:5 +error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied + --> $DIR/issue-46989.rs:40:18 | -LL | / trait Foo { -LL | | -LL | | } - | |_- trait `Foo` defined here +LL | fn assert_foo() {} + | --- required by this bound in `assert_foo` ... -LL | assert_foo::(); - | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough +LL | assert_foo::(); + | ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)` | - = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)` - = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0` + = help: the following implementations were found: + error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-57362-1.rs b/src/test/ui/issues/issue-57362-1.rs index 3ba82300fabea..1fa417fe98ab7 100644 --- a/src/test/ui/issues/issue-57362-1.rs +++ b/src/test/ui/issues/issue-57362-1.rs @@ -17,7 +17,7 @@ impl Trait for fn(&T) { fn f() { let a: fn(_) = |_: &u8| {}; - a.f(); //~ ERROR implementation of `Trait` is not general enough + a.f(); //~ ERROR no method named `f` } fn main() {} diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr index 24408420b1373..5c611cd43d3cc 100644 --- a/src/test/ui/issues/issue-57362-1.stderr +++ b/src/test/ui/issues/issue-57362-1.stderr @@ -1,16 +1,17 @@ -error: implementation of `Trait` is not general enough +error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current scope --> $DIR/issue-57362-1.rs:20:7 | -LL | / trait Trait { -LL | | fn f(self); -LL | | } - | |_- trait `Trait` defined here -... -LL | a.f(); - | ^ implementation of `Trait` is not general enough +LL | a.f(); + | ^ method not found in `fn(&u8)` | - = note: `Trait` would have to be implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`... - = note: ...but `Trait` is actually implemented for the type `for<'r> fn(&'r u8)` + = note: `a` is a function, perhaps you wish to call it + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `f`, perhaps you need to implement it + --> $DIR/issue-57362-1.rs:8:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-57362-2.rs b/src/test/ui/issues/issue-57362-2.rs index 7b6594abc9647..870d7f28ba953 100644 --- a/src/test/ui/issues/issue-57362-2.rs +++ b/src/test/ui/issues/issue-57362-2.rs @@ -19,9 +19,7 @@ impl<'a> X for fn(&'a ()) { } fn g() { - let x = ::make_g(); - //~^ ERROR implementation of `X` is not general enough - //~| ERROR implementation of `X` is not general enough + let x = ::make_g(); //~ ERROR no function or associated item } fn main() {} diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index dfd48ec22275b..2edc009746455 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -1,33 +1,16 @@ -error: implementation of `X` is not general enough - --> $DIR/issue-57362-2.rs:22:13 +error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'r> fn(&'r ())` in the current scope + --> $DIR/issue-57362-2.rs:22:25 | -LL | / trait X { -LL | | type G; -LL | | fn make_g() -> Self::G; -LL | | } - | |_- trait `X` defined here -... -LL | let x = ::make_g(); - | ^^^^^^^^^^^^^^^^^^ implementation of `X` is not general enough +LL | let x = ::make_g(); + | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` | - = note: `X` would have to be implemented for the type `for<'r> fn(&'r ())` - = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` - -error: implementation of `X` is not general enough - --> $DIR/issue-57362-2.rs:22:13 - | -LL | / trait X { -LL | | type G; -LL | | fn make_g() -> Self::G; - | | ----------------------- due to a where-clause on `X::make_g`... -LL | | } - | |_- trait `X` defined here -... -LL | let x = ::make_g(); - | ^^^^^^^^^^^^^^^^^^ doesn't satisfy where-clause + = help: items from traits can only be used if the trait is implemented and in scope +note: `X` defines an item `make_g`, perhaps you need to implement it + --> $DIR/issue-57362-2.rs:8:1 | - = note: ...`X` would have to be implemented for the type `for<'r> fn(&'r ())` - = note: ...but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` +LL | trait X { + | ^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs index 5e24a99bcc331..bc7b787cd65ac 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.rs +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -3,21 +3,21 @@ // error. However, now that we handle subtyping correctly, we no // longer get an error, because we recognize these two types as // equivalent! +// +// Whoops -- now that we reinstituted the leak-check, we get an error +// again. fn foo( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { - // The two types above are actually equivalent. With the older - // leak check, though, we didn't consider them as equivalent, and - // hence we gave errors. But now we've fixed that. let z = match 22 { 0 => x, - _ => y, + _ => y, //~ ERROR `match` arms have incompatible types }; } -fn foo_cast( +fn bar( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { @@ -28,30 +28,5 @@ fn foo_cast( }; } -fn bar( - x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, - y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, -) { - // The two types above are not equivalent. With the older LUB/GLB - // algorithm, this may have worked (I don't remember), but now it - // doesn't because we require equality. - let z = match 22 { - 0 => x, - _ => y, //~ ERROR `match` arms have incompatible types - }; -} - -fn bar_cast( - x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, - y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, -) { - // But we can *upcast* explicitly the type of `x` and figure - // things out: - let z = match 22 { - 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, - _ => y, - }; -} - fn main() { } diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr index d242fb7789aa1..6d5d51174699f 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -1,17 +1,17 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/old-lub-glb-hr.rs:40:14 + --> $DIR/old-lub-glb-hr.rs:16:14 | LL | let z = match 22 { | _____________- LL | | 0 => x, - | | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + | | - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)` LL | | _ => y, - | | ^ expected bound lifetime parameter 'a, found concrete lifetime + | | ^ expected bound lifetime parameter, found concrete lifetime LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` - found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` + = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)` + found fn pointer `for<'a> fn(&'a u8, &'a u8)` error: aborting due to previous error diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 7848f770a70cf..27704b3e0a8c7 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -11,10 +11,10 @@ error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | LL | want_G(baz); - | ^^^ one type is more general than the other + | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S` - found fn pointer `for<'r> fn(&'r S) -> &'r S` + found fn item `for<'r> fn(&'r S) -> &'r S {baz}` error: aborting due to 2 previous errors diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs index 0ce38e69f6b0f..31174fd4cf163 100644 --- a/src/test/ui/where-clauses/where-for-self-2.rs +++ b/src/test/ui/where-clauses/where-for-self-2.rs @@ -18,5 +18,5 @@ fn foo(x: &T) {} fn main() { - foo(&X); //~ ERROR implementation of `Bar` is not general enough + foo(&X); //~ ERROR trait bound } diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index b3cadf5b1b078..9976243b200dc 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,16 +1,17 @@ -error: implementation of `Bar` is not general enough +error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied --> $DIR/where-for-self-2.rs:21:5 | -LL | / trait Bar { -LL | | fn bar(&self); -LL | | } - | |_- trait `Bar` defined here +LL | fn foo(x: &T) + | --- required by a bound in this +LL | where for<'a> &'a T: Bar + | --- required by this bound in `foo` ... -LL | foo(&X); - | ^^^ implementation of `Bar` is not general enough +LL | foo(&X); + | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` | - = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... - = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` + = help: the following implementations were found: + <&'static u32 as Bar> error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. From f2cf9944831f15b1940da85c8fb1b419dec9f074 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 19 May 2020 01:09:40 +0000 Subject: [PATCH 19/30] rewrite leak check to be based on universes In the new leak check, instead of getting a list of placeholders to track, we look for any placeholder that is part of a universe which was created during the snapshot. We are looking for the following error patterns: * P1: P2, where P1 != P2 * P1: R, where R is in some universe that cannot name P1 This new leak check is more precise than before, in that it accepts this patterns: * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n * R: P1, R: P2, as above Note that this leak check, when running during subtyping, is less efficient than before in some sense because it is going to check and re-check all the universes created since the snapshot. We're going to move when the leak check runs to try and correct that. --- src/librustc_infer/infer/higher_ranked/mod.rs | 7 +- src/librustc_infer/infer/mod.rs | 8 +- .../infer/region_constraints/leak_check.rs | 521 ++++++++++++++---- src/librustc_infer/lib.rs | 3 + .../traits/project.rs | 12 +- .../traits/select/mod.rs | 19 +- .../associated-types-eq-hr.stderr | 4 +- ...pe.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 6 +- .../hr-subtype.bound_a_b_vs_bound_a.stderr | 6 +- .../hr-subtype.bound_a_vs_bound_a.stderr | 4 +- .../hr-subtype.bound_a_vs_bound_b.stderr | 4 +- .../hr-subtype.bound_a_vs_free_x.stderr | 6 +- ...-subtype.bound_co_a_b_vs_bound_co_a.stderr | 23 +- ...ubtype.bound_co_a_co_b_ret_contra_a.stderr | 23 +- ...hr-subtype.bound_co_a_vs_bound_co_b.stderr | 4 +- ...pe.bound_contra_a_contra_b_ret_co_a.stderr | 6 +- ...ubtype.bound_inv_a_b_vs_bound_inv_a.stderr | 6 +- ...-subtype.bound_inv_a_vs_bound_inv_b.stderr | 4 +- ...hr-subtype.free_inv_x_vs_free_inv_y.stderr | 56 +- .../hr-subtype.free_x_vs_free_x.stderr | 4 +- .../hr-subtype.free_x_vs_free_y.stderr | 28 +- src/test/ui/hr-subtype/hr-subtype.rs | 64 ++- .../hrtb-exists-forall-trait-covariant.rs | 5 +- .../hrtb-exists-forall-trait-covariant.stderr | 18 - ...regions-fn-subtyping-return-static-fail.rs | 11 +- ...ons-fn-subtyping-return-static-fail.stderr | 11 +- .../regions-fn-subtyping-return-static.rs | 13 +- .../regions-fn-subtyping-return-static.stderr | 12 - src/test/ui/rfc1623.stderr | 2 +- 29 files changed, 571 insertions(+), 319 deletions(-) delete mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr delete mode 100644 src/test/ui/regions/regions-fn-subtyping-return-static.stderr diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs index 0499dc9ed2232..b94221785ae75 100644 --- a/src/librustc_infer/infer/higher_ranked/mod.rs +++ b/src/librustc_infer/infer/higher_ranked/mod.rs @@ -33,7 +33,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { self.infcx.commit_if_ok(|snapshot| { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. - let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b); + let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- @@ -48,7 +48,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // Compare types now that bound regions have been replaced. let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?; + self.infcx.leak_check(!a_is_expected, snapshot)?; debug!("higher_ranked_sub: OK result={:?}", result); @@ -119,7 +119,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn leak_check( &self, overly_polymorphic: bool, - placeholder_map: &PlaceholderMap<'tcx>, snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> RelateResult<'tcx, ()> { // If the user gave `-Zno-leak-check`, or we have been @@ -135,7 +134,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.inner.borrow_mut().unwrap_region_constraints().leak_check( self.tcx, overly_polymorphic, - placeholder_map, + self.universe(), snapshot, ) } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 91f4b3323f30e..0e569be34aa66 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -992,12 +992,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } Some(self.commit_if_ok(|snapshot| { - let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) = + let (ty::SubtypePredicate { a_is_expected, a, b }, _) = self.replace_bound_vars_with_placeholders(&predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; - self.leak_check(false, &placeholder_map, snapshot)?; + self.leak_check(false, snapshot)?; Ok(ok.unit()) })) @@ -1009,13 +1009,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { - let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = + let (ty::OutlivesPredicate(r_a, r_b), _) = self.replace_bound_vars_with_placeholders(&predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, &placeholder_map, snapshot)?; + self.leak_check(false, snapshot)?; Ok(()) }) } diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 91c39a0e78ffb..f3b78909b42d8 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -1,158 +1,445 @@ use super::*; -use crate::infer::{CombinedSnapshot, PlaceholderMap}; -use rustc_data_structures::undo_log::UndoLogs; +use crate::infer::CombinedSnapshot; +use rustc_data_structures::{ + graph::{scc::Sccs, vec_graph::VecGraph}, + undo_log::UndoLogs, +}; +use rustc_index::vec::Idx; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; impl<'tcx> RegionConstraintCollector<'_, 'tcx> { - /// Searches region constraints created since `snapshot` that - /// affect one of the placeholders in `placeholder_map`, returning - /// an error if any of the placeholders are related to another - /// placeholder or would have to escape into some parent universe - /// that cannot name them. + /// Searches new universes created during `snapshot`, looking for + /// placeholders that may "leak" out from the universes they are contained + /// in. If any leaking placeholders are found, then an `Err` is returned + /// (typically leading to the snapshot being reversed). /// - /// This is a temporary backwards compatibility measure to try and - /// retain the older (arguably incorrect) behavior of the - /// compiler. + /// The leak check *used* to be the only way we had to handle higher-ranked + /// obligations. Now that we have integrated universes into the region + /// solvers, this is no longer the case, but we retain the leak check for + /// backwards compatibility purposes. In particular, it lets us make "early" + /// decisions about whether a region error will be reported that are used in + /// coherence and elsewhere -- see #56105 and #59490 for more details. The + /// eventual fate of the leak checker is not yet settled. /// - /// NB. Although `_snapshot` isn't used, it's passed in to prove - /// that we are in a snapshot, which guarantees that we can just - /// search the "undo log" for edges. This is mostly an efficiency - /// thing -- we could search *all* region constraints, but that'd be - /// a bigger set and the data structures are not setup for that. If - /// we wind up keeping some form of this check long term, it would - /// probably be better to remove the snapshot parameter and to - /// refactor the constraint set. + /// The leak checker works by searching for the following error patterns: + /// + /// * P1: P2, where P1 != P2 + /// * P1: R, where R is in some universe that cannot name P1 + /// + /// The idea here is that each of these patterns represents something that + /// the region solver would eventually report as an error, so we can detect + /// the error early. There is a fly in the ointment, though, in that this is + /// not entirely true. In particular, in the future, we may extend the + /// environment with implied bounds or other info about how placeholders + /// relate to regions in outer universes. In that case, `P1: R` for example + /// might become solveable. + /// + /// # Summary of the implementation + /// + /// The leak checks as follows. First, we construct a graph where `R2: R1` + /// implies `R2 -> R1`, and we compute the SCCs. + /// + /// For each SCC S, we compute: + /// + /// * what placeholder P it must be equal to, if any + /// * if there are multiple placeholders that must be equal, report an error because `P1: P2` + /// * the minimum universe of its constituents + /// + /// Then we walk the SCCs in dependency order and compute + /// + /// * what placeholder they must outlive transitively + /// * if they must also be equal to a placeholder, report an error because `P1: P2` + /// * minimum universe U of all SCCs they must outlive + /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that + /// indicates `P: R` and `R` is in an incompatible universe + /// + /// # Historical note + /// + /// Older variants of the leak check used to report errors for these + /// patterns, but we no longer do: + /// + /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n + /// * R: P1, R: P2, as above pub fn leak_check( &mut self, tcx: TyCtxt<'tcx>, overly_polymorphic: bool, - placeholder_map: &PlaceholderMap<'tcx>, - _snapshot: &CombinedSnapshot<'_, 'tcx>, + max_universe: ty::UniverseIndex, + snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> RelateResult<'tcx, ()> { - debug!("leak_check(placeholders={:?})", placeholder_map); + debug!( + "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})", + max_universe, snapshot.universe, overly_polymorphic + ); assert!(UndoLogs::>::in_snapshot(&self.undo_log)); - // Go through each placeholder that we created. - for &placeholder_region in placeholder_map.values() { - // Find the universe this placeholder inhabits. - let placeholder = match placeholder_region { - ty::RePlaceholder(p) => p, - _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,), - }; - - // Find all regions that are related to this placeholder - // in some way. This means any region that either outlives - // or is outlived by a placeholder. - let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); - taint_set.fixed_point( - tcx, - self.undo_log.region_constraints(), - &self.storage.data.verifys, - ); - let tainted_regions = taint_set.into_set(); - - // Report an error if two placeholders in the same universe - // are related to one another, or if a placeholder is related - // to something from a parent universe. - for &tainted_region in &tainted_regions { - if let ty::RePlaceholder(_) = tainted_region { - // Two placeholders cannot be related: - if tainted_region == placeholder_region { - continue; - } - } else if self.universe(tainted_region).can_name(placeholder.universe) { - continue; - } - - return Err(if overly_polymorphic { - debug!("overly polymorphic!"); - TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region) - } else { - debug!("not as polymorphic!"); - TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region) - }); - } + let universe_at_start_of_snapshot = snapshot.universe; + if universe_at_start_of_snapshot == max_universe { + return Ok(()); } + let mini_graph = + &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys); + + let mut leak_check = LeakCheck::new( + tcx, + universe_at_start_of_snapshot, + max_universe, + overly_polymorphic, + mini_graph, + self, + ); + leak_check.assign_placeholder_values()?; + leak_check.propagate_scc_value()?; Ok(()) } } -#[derive(Debug)] -struct TaintSet<'tcx> { - directions: TaintDirections, - regions: FxHashSet>, +struct LeakCheck<'me, 'tcx> { + tcx: TyCtxt<'tcx>, + universe_at_start_of_snapshot: ty::UniverseIndex, + overly_polymorphic: bool, + mini_graph: &'me MiniGraph<'tcx>, + rcc: &'me RegionConstraintCollector<'me, 'tcx>, + + // Initially, for each SCC S, stores a placeholder `P` such that `S = P` + // must hold. + // + // Later, during the [`LeakCheck::propagate_scc_value`] function, this array + // is repurposed to store some placeholder `P` such that the weaker + // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1 + // = P`.) + scc_placeholders: IndexVec>, + + // For each SCC S, track the minimum universe that flows into it. Note that + // this is both the minimum of the universes for every region that is a + // member of the SCC, but also if you have `R1: R2`, then the universe of + // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To + // see that, imagine that you have `P1: R` -- in that case, `R` must be + // either the placeholder `P1` or the empty region in that same universe. + // + // To detect errors, we look for an SCC S where the values in + // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`. + scc_universes: IndexVec>, } -impl<'tcx> TaintSet<'tcx> { - fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self { - let mut regions = FxHashSet::default(); - regions.insert(initial_region); - TaintSet { directions, regions } +impl<'me, 'tcx> LeakCheck<'me, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + universe_at_start_of_snapshot: ty::UniverseIndex, + max_universe: ty::UniverseIndex, + overly_polymorphic: bool, + mini_graph: &'me MiniGraph<'tcx>, + rcc: &'me RegionConstraintCollector<'me, 'tcx>, + ) -> Self { + let dummy_scc_universe = SccUniverse { universe: max_universe, region: None }; + Self { + tcx, + universe_at_start_of_snapshot, + overly_polymorphic, + mini_graph, + rcc, + scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), + scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()), + } + } + + /// Compute what placeholders (if any) each SCC must be equal to. + /// Also compute the minimum universe of all the regions in each SCC. + fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> { + // First walk: find each placeholder that is from a newly created universe. + for (region, leak_check_node) in &self.mini_graph.nodes { + let scc = self.mini_graph.sccs.scc(*leak_check_node); + + // Set the universe of each SCC to be the minimum of its constituent universes + let universe = self.rcc.universe(region); + debug!( + "assign_placeholder_values: scc={:?} universe={:?} region={:?}", + scc, universe, region + ); + self.scc_universes[scc].take_min(universe, region); + + // Detect those SCCs that directly contain a placeholder + if let ty::RePlaceholder(placeholder) = region { + if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) { + self.assign_scc_value(scc, *placeholder)?; + } + } + } + + Ok(()) } - fn fixed_point<'a>( + // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold. + // This may create an error. + fn assign_scc_value( &mut self, - tcx: TyCtxt<'tcx>, - undo_log: impl IntoIterator> + Clone, - verifys: &[Verify<'tcx>], - ) where - 'tcx: 'a, - { - let mut prev_len = 0; - while prev_len < self.len() { - debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len()); - - prev_len = self.len(); - - for undo_entry in undo_log.clone() { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::RegSubVar(a, b)) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::VarSubReg(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), b); - } - &AddConstraint(Constraint::RegSubReg(a, b)) => { - self.add_edge(a, b); - } - &AddGiven(a, b) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddVerify(i) => span_bug!( - verifys[i].origin.span(), - "we never add verifications while doing higher-ranked things", - ), - &AddCombination(..) | &AddVar(..) => {} + scc: LeakCheckScc, + placeholder: ty::PlaceholderRegion, + ) -> RelateResult<'tcx, ()> { + match self.scc_placeholders[scc] { + Some(p) => { + assert_ne!(p, placeholder); + return Err(self.placeholder_error(p, placeholder)); + } + None => { + self.scc_placeholders[scc] = Some(placeholder); + } + }; + + Ok(()) + } + + /// For each SCC S, iterate over each successor S1 where `S: S1`: + /// + /// * Compute + /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`, + /// `universe(S) <= universe(S1)`. This executes after + /// `assign_placeholder_values`, so `universe(S)` is already the minimum + /// universe of any of its direct constituents. + fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> { + // Loop invariants: + // + // On start of the loop iteration for `scc1`: + // + // * `scc_universes[scc1]` contains the minimum universe of the + // constituents of `scc1` + // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must + // be equal to (if any) + // + // For each succssor `scc2` where `scc1: scc2`: + // + // * `scc_placeholder[scc2]` stores some placeholder `P` where + // `scc2: P` (if any) + // * `scc_universes[scc2]` contains the minimum universe of the + // constituents of `scc2` and any of its successors + for scc1 in self.mini_graph.sccs.all_sccs() { + debug!( + "propagate_scc_value: scc={:?} with universe {:?}", + scc1, self.scc_universes[scc1] + ); + + // Walk over each `scc2` such that `scc1: scc2` and compute: + // + // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1` + // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple, + // we pick one arbitrarily) + let mut scc1_universe = self.scc_universes[scc1]; + let mut succ_bound = None; + for &scc2 in self.mini_graph.sccs.successors(scc1) { + let SccUniverse { universe: scc2_universe, region: scc2_region } = + self.scc_universes[scc2]; + + scc1_universe.take_min(scc2_universe, scc2_region.unwrap()); + + if let Some(b) = self.scc_placeholders[scc2] { + succ_bound = Some(b); } } + + // Update minimum universe of scc1. + self.scc_universes[scc1] = scc1_universe; + + // At this point, `scc_placholder[scc1]` stores the placeholder that + // `scc1` must be equal to, if any. + if let Some(scc1_placeholder) = self.scc_placeholders[scc1] { + debug!( + "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}", + scc1, scc1_placeholder, scc1_universe + ); + + // Check if `P1: R` for some `R` in a universe that cannot name + // P1. That's an error. + if scc1_universe.universe.cannot_name(scc1_placeholder.universe) { + return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap())); + } + + // Check if we have some placeholder where `S: P2` + // (transitively). In that case, since `S = P1`, that implies + // `P1: P2`, which is an error condition. + if let Some(scc2_placeholder) = succ_bound { + assert_ne!(scc1_placeholder, scc2_placeholder); + return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder)); + } + } else { + // Otherwise, we can reach a placeholder if some successor can. + self.scc_placeholders[scc1] = succ_bound; + } + + // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any). } + Ok(()) } - fn into_set(self) -> FxHashSet> { - self.regions + fn placeholder_error( + &self, + placeholder1: ty::PlaceholderRegion, + placeholder2: ty::PlaceholderRegion, + ) -> TypeError<'tcx> { + self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2))) } - fn len(&self) -> usize { - self.regions.len() + fn error( + &self, + placeholder: ty::PlaceholderRegion, + other_region: ty::Region<'tcx>, + ) -> TypeError<'tcx> { + if self.overly_polymorphic { + return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region); + } else { + return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region); + } } +} - fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) { - if self.directions.incoming { - if self.regions.contains(&target) { - self.regions.insert(source); - } +// States we need to distinguish: +// +// * must be equal to a placeholder (i.e., a placeholder is in the SCC) +// * it could conflict with some other regions in the SCC in different universes +// * or a different placeholder +// * `P1: S` and `S` must be equal to a placeholder +// * `P1: S` and `S` is in an incompatible universe +// +// So if we +// +// (a) compute which placeholder (if any) each SCC must be equal to +// (b) compute its minimum universe +// (c) compute *some* placeholder where `S: P1` (any one will do) +// +// then we get an error if: +// +// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1` +// - `S: P1` and minimum universe cannot name `P1` +// - `S: P1` and we must be equal to `P2` +// +// So we want to track: +// +// * Equal placeholder (if any) +// * Some bounding placeholder (if any) +// * Minimum universe +// +// * We compute equal placeholder + minimum universe of constituents in first pass +// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`) +// * bounding placeholder (if any) +// * minimum universe +// * And if we must be equal to a placeholder then we check it against +// * minimum universe +// * no bounding placeholder + +/// Tracks the "minimum universe" for each SCC, along with some region that +/// caused it to change. +#[derive(Copy, Clone, Debug)] +struct SccUniverse<'tcx> { + /// For some SCC S, the minimum universe of: + /// + /// * each region R in S + /// * each SCC S1 such that S: S1 + universe: ty::UniverseIndex, + + /// Some region that caused `universe` to be what it is. + region: Option>, +} + +impl<'tcx> SccUniverse<'tcx> { + /// If `universe` is less than our current universe, then update + /// `self.universe` and `self.region`. + fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) { + if universe < self.universe || self.region.is_none() { + self.universe = universe; + self.region = Some(region); } + } +} + +rustc_index::newtype_index! { + struct LeakCheckNode { + DEBUG_FORMAT = "LeakCheckNode({})" + } +} - if self.directions.outgoing { - if self.regions.contains(&source) { - self.regions.insert(target); +rustc_index::newtype_index! { + struct LeakCheckScc { + DEBUG_FORMAT = "LeakCheckScc({})" + } +} + +/// Represents the graph of constraints. For each `R1: R2` constraint we create +/// an edge `R1 -> R2` in the graph. +struct MiniGraph<'tcx> { + /// Map from a region to the index of the node in the graph. + nodes: FxHashMap, LeakCheckNode>, + + /// Map from node index to SCC, and stores the successors of each SCC. All + /// the regions in the same SCC are equal to one another, and if `S1 -> S2`, + /// then `S1: S2`. + sccs: Sccs, +} + +impl<'tcx> MiniGraph<'tcx> { + fn new<'a>( + tcx: TyCtxt<'tcx>, + undo_log: impl Iterator>, + verifys: &[Verify<'tcx>], + ) -> Self + where + 'tcx: 'a, + { + let mut nodes = FxHashMap::default(); + let mut edges = Vec::new(); + + // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter. + Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| { + let source_node = Self::add_node(&mut nodes, source); + let target_node = Self::add_node(&mut nodes, target); + edges.push((source_node, target_node)); + }); + let graph = VecGraph::new(nodes.len(), edges); + let sccs = Sccs::new(&graph); + Self { nodes, sccs } + } + + /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1` + fn iterate_undo_log<'a>( + tcx: TyCtxt<'tcx>, + undo_log: impl Iterator>, + verifys: &[Verify<'tcx>], + mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), + ) where + 'tcx: 'a, + { + for undo_entry in undo_log { + match undo_entry { + &AddConstraint(Constraint::VarSubVar(a, b)) => { + each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); + } + &AddConstraint(Constraint::RegSubVar(a, b)) => { + each_edge(a, tcx.mk_region(ReVar(b))); + } + &AddConstraint(Constraint::VarSubReg(a, b)) => { + each_edge(tcx.mk_region(ReVar(a)), b); + } + &AddConstraint(Constraint::RegSubReg(a, b)) => { + each_edge(a, b); + } + &AddGiven(a, b) => { + each_edge(a, tcx.mk_region(ReVar(b))); + } + &AddVerify(i) => span_bug!( + verifys[i].origin.span(), + "we never add verifications while doing higher-ranked things", + ), + &AddCombination(..) | &AddVar(..) => {} } } } + + fn add_node( + nodes: &mut FxHashMap, LeakCheckNode>, + r: ty::Region<'tcx>, + ) -> LeakCheckNode { + let l = nodes.len(); + *nodes.entry(r).or_insert(LeakCheckNode::new(l)) + } } diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index ed04ee02b7203..0f3f3db867959 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -16,6 +16,9 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] +#![feature(const_if_match)] +#![feature(const_panic)] #![feature(extend_one)] #![feature(never_type)] #![feature(or_patterns)] diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 574d50a4fccc2..4bc58fbaadcda 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -150,14 +150,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|snapshot| { - let (placeholder_predicate, placeholder_map) = + let (placeholder_predicate, _) = infcx.replace_bound_vars_with_placeholders(&obligation.predicate); let placeholder_obligation = obligation.with(placeholder_predicate); let result = project_and_unify_type(selcx, &placeholder_obligation)?; - infcx - .leak_check(false, &placeholder_map, snapshot) - .map_err(|err| MismatchedProjectionTypes { err })?; + infcx.leak_check(false, snapshot).map_err(|err| MismatchedProjectionTypes { err })?; Ok(result) }) } @@ -300,7 +298,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { fn fold>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); - if !value.has_projections() { value } else { value.fold_with(self) } + if !value.has_projections() { + value + } else { + value.fold_with(self) + } } } diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 076bdad423ab8..e90acbbce67ba 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -21,7 +21,7 @@ use super::{Normalized, ProjectionCacheKey}; use super::{ObligationCause, PredicateObligation, TraitObligation}; use super::{Overflow, SelectionError, Unimplemented}; -use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; +use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectionCacheKeyExt; use rustc_ast::attr; @@ -1265,7 +1265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> bool { let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - let (placeholder_trait_predicate, placeholder_map) = + let (placeholder_trait_predicate, _) = self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( "match_projection_obligation_against_definition_bounds: \ @@ -1297,7 +1297,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation, bound, placeholder_trait_predicate.trait_ref, - &placeholder_map, snapshot, ) }) { @@ -1320,7 +1319,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation, bound, placeholder_trait_predicate.trait_ref, - &placeholder_map, snapshot, ); @@ -1335,7 +1333,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_bound: ty::PolyTraitRef<'tcx>, placeholder_trait_ref: ty::TraitRef<'tcx>, - placeholder_map: &PlaceholderMap<'tcx>, snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> bool { debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); @@ -1343,7 +1340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&obligation.cause, obligation.param_env) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .is_ok() - && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok() + && self.infcx.leak_check(false, snapshot).is_ok() } fn evaluate_where_clause<'o>( @@ -1837,7 +1834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let (placeholder_obligation, placeholder_map) = + let (placeholder_obligation, _) = self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; @@ -1869,7 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; nested_obligations.extend(obligations); - if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) { + if let Err(e) = self.infcx.leak_check(false, snapshot) { debug!("match_impl: failed leak check due to `{}`", e); return Err(()); } @@ -2405,7 +2402,11 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { } fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } + if let Some(head) = self.head { + head.depth + } else { + 0 + } } } diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 58d72746e76aa..50f1d07142f8c 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -49,7 +49,7 @@ LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> | ------------- required by this bound in `tuple_one` ... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:97:17 @@ -74,7 +74,7 @@ LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> | ------------- required by this bound in `tuple_two` ... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:107:18 diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index b91798fa12379..1da224a3e85e0 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -1,12 +1,12 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, -LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } - | |_________________________________________________________________________________________- in this macro invocation +LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } + | |_____________________________________________- in this macro invocation | = note: expected enum `std::option::Option fn(&'a u32, &'b u32) -> &'a u32>` found enum `std::option::Option fn(&'a u32, &'a u32) -> &'a u32>` diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index 45f53d4fe99db..880a8c7be8305 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,12 +1,12 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), -LL | | for<'a> fn(&'a u32, &'a u32)) } - | |__________________________________________________________________- in this macro invocation +LL | | for<'a> fn(&'a u32, &'a u32)) } + | |__________________________________- in this macro invocation | = note: expected enum `std::option::Option fn(&'a u32, &'b u32)>` found enum `std::option::Option fn(&'a u32, &'a u32)>` diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 6aba6466fada5..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:104:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 6aba6466fada5..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:104:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index c3e4f6d2ed0c1..d2abcc4a66091 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -1,12 +1,12 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), -LL | | fn(&'x u32)) } - | |___________________________________________- in this macro invocation +LL | | fn(&'x u32)) } + | |______________- in this macro invocation | = note: expected enum `std::option::Option fn(&'a u32)>` found enum `std::option::Option` diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index 4d7b86027f564..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:104:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), -LL | | for<'a> fn(Co<'a>, Co<'a>)) } - | |______________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>)>` - found enum `std::option::Option fn(Co<'a>, Co<'a>)>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index 7f0a4197dd7fe..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:104:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, -LL | | for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } - | |______________________________________________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Co<'a>, Co<'b>) -> Contra<'a>>` - found enum `std::option::Option fn(Co<'a>, Co<'a>) -> Contra<'a>>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 6aba6466fada5..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:104:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index c12e543a44e79..e1a16f5149cc6 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,12 +1,12 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, -LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } - | |______________________________________________________________________________________________- in this macro invocation +LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } + | |__________________________________________________- in this macro invocation | = note: expected enum `std::option::Option fn(Contra<'a>, Contra<'b>) -> Co<'a>>` found enum `std::option::Option fn(Contra<'a>, Contra<'a>) -> Co<'a>>` diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 460356856bd56..5fec1e9a92eae 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -1,12 +1,12 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a ... LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), -LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } - | |__________________________________________________________________________- in this macro invocation +LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } + | |__________________________________- in this macro invocation | = note: expected enum `std::option::Option fn(Inv<'a>, Inv<'b>)>` found enum `std::option::Option fn(Inv<'a>, Inv<'a>)>` diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 6aba6466fada5..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:104:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr index fc3643306e628..3c8af20e50cef 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr @@ -1,65 +1,65 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:33:26 + --> $DIR/hr-subtype.rs:39:26 | LL | gimme::<$t2>(None::<$t1>); | ^^^^^^^^^^^ lifetime mismatch ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation | = note: expected enum `std::option::Option)>` found enum `std::option::Option)>` -note: the lifetime `'x` as defined on the function body at 32:20... - --> $DIR/hr-subtype.rs:32:20 +note: the lifetime `'x` as defined on the function body at 38:20... + --> $DIR/hr-subtype.rs:38:20 | -LL | fn subtype<'x,'y:'x,'z:'y>() { +LL | fn subtype<'x, 'y: 'x, 'z: 'y>() { | ^^ ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23 - --> $DIR/hr-subtype.rs:32:23 +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation +note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24 + --> $DIR/hr-subtype.rs:38:24 | -LL | fn subtype<'x,'y:'x,'z:'y>() { - | ^^ +LL | fn subtype<'x, 'y: 'x, 'z: 'y>() { + | ^^ ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ lifetime mismatch ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation | = note: expected enum `std::option::Option)>` found enum `std::option::Option)>` -note: the lifetime `'x` as defined on the function body at 38:22... - --> $DIR/hr-subtype.rs:38:22 +note: the lifetime `'x` as defined on the function body at 44:22... + --> $DIR/hr-subtype.rs:44:22 | -LL | fn supertype<'x,'y:'x,'z:'y>() { +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { | ^^ ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25 - --> $DIR/hr-subtype.rs:38:25 +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation +note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26 + --> $DIR/hr-subtype.rs:44:26 | -LL | fn supertype<'x,'y:'x,'z:'y>() { - | ^^ +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { + | ^^ ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 6aba6466fada5..0cc30e479c7b9 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,11 +1,11 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:100:1 + --> $DIR/hr-subtype.rs:104:1 | LL | / fn main() { LL | | LL | | LL | | -LL | | +... | LL | | LL | | } | |_^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr index 0dde27788f629..7b4cdd4a419b4 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr @@ -1,33 +1,33 @@ error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:39:26 + --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^ lifetime mismatch ... LL | / check! { free_x_vs_free_y: (fn(&'x u32), -LL | | fn(&'y u32)) } - | |__________________________________________- in this macro invocation +LL | | fn(&'y u32)) } + | |______________- in this macro invocation | = note: expected enum `std::option::Option` found enum `std::option::Option` -note: the lifetime `'x` as defined on the function body at 38:22... - --> $DIR/hr-subtype.rs:38:22 +note: the lifetime `'x` as defined on the function body at 44:22... + --> $DIR/hr-subtype.rs:44:22 | -LL | fn supertype<'x,'y:'x,'z:'y>() { +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { | ^^ ... LL | / check! { free_x_vs_free_y: (fn(&'x u32), -LL | | fn(&'y u32)) } - | |__________________________________________- in this macro invocation -note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25 - --> $DIR/hr-subtype.rs:38:25 +LL | | fn(&'y u32)) } + | |______________- in this macro invocation +note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26 + --> $DIR/hr-subtype.rs:44:26 | -LL | fn supertype<'x,'y:'x,'z:'y>() { - | ^^ +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { + | ^^ ... LL | / check! { free_x_vs_free_y: (fn(&'x u32), -LL | | fn(&'y u32)) } - | |__________________________________________- in this macro invocation +LL | | fn(&'y u32)) } + | |______________- in this macro invocation = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs index b31f198bd97bf..9e9c2ce9c61d7 100644 --- a/src/test/ui/hr-subtype/hr-subtype.rs +++ b/src/test/ui/hr-subtype/hr-subtype.rs @@ -18,24 +18,30 @@ // revisions: bound_inv_a_b_vs_bound_inv_a // revisions: bound_a_b_ret_a_vs_bound_a_ret_a -fn gimme(_: Option) { } +fn gimme(_: Option) {} -struct Inv<'a> { x: *mut &'a u32 } +struct Inv<'a> { + x: *mut &'a u32, +} -struct Co<'a> { x: fn(&'a u32) } +struct Co<'a> { + x: fn(&'a u32), +} -struct Contra<'a> { x: &'a u32 } +struct Contra<'a> { + x: &'a u32, +} macro_rules! check { ($rev:ident: ($t1:ty, $t2:ty)) => { #[cfg($rev)] - fn subtype<'x,'y:'x,'z:'y>() { + fn subtype<'x, 'y: 'x, 'z: 'y>() { gimme::<$t2>(None::<$t1>); //[free_inv_x_vs_free_inv_y]~^ ERROR } #[cfg($rev)] - fn supertype<'x,'y:'x,'z:'y>() { + fn supertype<'x, 'y: 'x, 'z: 'y>() { gimme::<$t1>(None::<$t2>); //[bound_a_vs_free_x]~^ ERROR //[free_x_vs_free_y]~^^ ERROR @@ -43,35 +49,33 @@ macro_rules! check { //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types - //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR - //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR - //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR + //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^ ERROR } - } + }; } // If both have bound regions, they are equivalent, regardless of // variant. check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32), - for<'a> fn(&'a u32)) } +for<'a> fn(&'a u32)) } check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32), - for<'b> fn(&'b u32)) } +for<'b> fn(&'b u32)) } check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>), - for<'b> fn(Inv<'b>)) } +for<'b> fn(Inv<'b>)) } check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>), - for<'b> fn(Co<'b>)) } +for<'b> fn(Co<'b>)) } // Bound is a subtype of free. check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), - fn(&'x u32)) } +fn(&'x u32)) } // Two free regions are relatable if subtyping holds. check! { free_x_vs_free_x: (fn(&'x u32), - fn(&'x u32)) } +fn(&'x u32)) } check! { free_x_vs_free_y: (fn(&'x u32), - fn(&'y u32)) } +fn(&'y u32)) } check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), - fn(Inv<'y>)) } +fn(Inv<'y>)) } // Somewhat surprisingly, a fn taking two distinct bound lifetimes and // a fn taking one bound lifetime can be interchangeable, but only if @@ -82,25 +86,27 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), // intersection; // - if we are contravariant, then 'a can be inferred to 'static. check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), - for<'a> fn(&'a u32, &'a u32)) } +for<'a> fn(&'a u32, &'a u32)) } check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), - for<'a> fn(Co<'a>, Co<'a>)) } +for<'a> fn(Co<'a>, Co<'a>)) } check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, - for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } +for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, - for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } +for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } // If we make those lifetimes invariant, then the two types are not interchangeable. check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), - for<'a> fn(Inv<'a>, Inv<'a>)) } +for<'a> fn(Inv<'a>, Inv<'a>)) } check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, - for<'a> fn(&'a u32, &'a u32) -> &'a u32) } +for<'a> fn(&'a u32, &'a u32) -> &'a u32) } #[rustc_error] fn main() { -//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error] -//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error] -//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error] -//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error] -//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error] + //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error] + //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error] + //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error] + //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error] + //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error] + //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR + //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs index 95b57d6c5bb5e..f95496a6c3cc0 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs @@ -2,6 +2,8 @@ // // In particular, we test this pattern in trait solving, where it is not connected // to any part of the source code. +// +// check-pass trait Trait {} @@ -30,9 +32,6 @@ fn main() { // - `?b: ?a` -- solveable if `?b` is inferred to `'static` // - So the subtyping check succeeds, somewhat surprisingly. // This is because we can use `'static`. - // - // NB. *However*, the reinstated leak-check gives an error here. foo::<()>(); - //~^ ERROR not satisfied } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr deleted file mode 100644 index 1e335f9ee9610..0000000000000 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the trait bound `(): Trait fn(fn(&'b u32))>` is not satisfied - --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11 - | -LL | fn foo() - | --- required by a bound in this -LL | where -LL | T: Trait fn(fn(&'b u32))>, - | ------------------------------ required by this bound in `foo` -... -LL | foo::<()>(); - | ^^ the trait `Trait fn(fn(&'b u32))>` is not implemented for `()` - | - = help: the following implementations were found: - <() as Trait> - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions-fn-subtyping-return-static-fail.rs index 2dd0c9796e258..539221b5a046c 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs @@ -13,11 +13,11 @@ struct S; // Given 'cx, return 'cx type F = for<'cx> fn(&'cx S) -> &'cx S; -fn want_F(f: F) { } +fn want_F(f: F) {} // Given anything, return 'static type G = for<'cx> fn(&'cx S) -> &'static S; -fn want_G(f: G) { } +fn want_G(f: G) {} // Should meet both. fn foo(x: &S) -> &'static S { @@ -25,7 +25,7 @@ fn foo(x: &S) -> &'static S { } // Should meet both. -fn bar<'a,'b>(x: &'a S) -> &'b S { +fn bar<'a, 'b>(x: &'a S) -> &'b S { panic!() } @@ -37,7 +37,7 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - want_F(bar); //~ ERROR mismatched types + want_F(bar); want_F(baz); } @@ -48,5 +48,4 @@ fn supply_G() { want_G(baz); //~ ERROR mismatched types } -pub fn main() { -} +pub fn main() {} diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 27704b3e0a8c7..6d75ace3c4698 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -1,12 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12 - | -LL | want_F(bar); - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx - | - = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` - error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | @@ -16,6 +7,6 @@ LL | want_G(baz); = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S` found fn item `for<'r> fn(&'r S) -> &'r S {baz}` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.rs b/src/test/ui/regions/regions-fn-subtyping-return-static.rs index fa2cc37d05b2b..de14d5ba82a1b 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs @@ -5,6 +5,8 @@ // *ANY* lifetime and returns a reference with the 'static lifetime. // This can safely be considered to be an instance of `F` because all // lifetimes are sublifetimes of 'static. +// +// check-pass #![allow(dead_code)] #![allow(unused_variables)] @@ -14,11 +16,11 @@ struct S; // Given 'cx, return 'cx type F = for<'cx> fn(&'cx S) -> &'cx S; -fn want_F(f: F) { } +fn want_F(f: F) {} // Given anything, return 'static type G = for<'cx> fn(&'cx S) -> &'static S; -fn want_G(f: G) { } +fn want_G(f: G) {} // Should meet both. fn foo(x: &S) -> &'static S { @@ -26,7 +28,7 @@ fn foo(x: &S) -> &'static S { } // Should meet both. -fn bar<'a,'b>(x: &'a S) -> &'b S { +fn bar<'a, 'b>(x: &'a S) -> &'b S { panic!() } @@ -38,10 +40,9 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - want_F(bar); //~ ERROR mismatched types + want_F(bar); want_F(baz); } -pub fn main() { -} +pub fn main() {} diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr deleted file mode 100644 index a8a7e97e6acf6..0000000000000 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static.rs:41:12 - | -LL | want_F(bar); - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx - | - = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index ca956004ef76f..75df99137179b 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -36,7 +36,7 @@ error[E0271]: type mismatch resolving `for<'a, 'b> _ {id::<_>} as std: --> $DIR/rfc1623.rs:25:8 | LL | f: &id, - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | ^^^ expected bound lifetime parameter 'b, found concrete lifetime | = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` From 5a7a850753b60abfd2a806bf6bba4259d3535e7b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 May 2020 10:19:36 +0000 Subject: [PATCH 20/30] move leak-check to during coherence, candidate eval In particular, it no longer occurs during the subtyping check. This is important for enabling lazy normalization, because the subtyping check will be producing sub-obligations that could affect its results. Consider an example like for<'a> fn(<&'a as Mirror>::Item) = fn(&'b u8) where `::Item = T` for all `T`. We will wish to produce a new subobligation like <'!1 as Mirror>::Item = &'b u8 This will, after being solved, ultimately yield a constraint that `'!1 = 'b` which will fail. But with the leak-check being performed on subtyping, there is no opportunity to normalize `<'!1 as Mirror>::Item` (unless we invoke that normalization directly from within subtyping, and I would prefer that subtyping and unification are distinct operations rather than part of the trait solving stack). The reason to keep the leak check during coherence and trait evaluation is partly for backwards compatibility. The coherence change permits impls for `fn(T)` and `fn(&T)` to co-exist, and the trait evaluation change means that we can distinguish those two cases without ambiguity errors. It also avoids recreating #57639, where we were incorrectly choosing a where clause that would have failed the leak check over the impl which succeeds. The other reason to keep the leak check in those places is that I think it is actually close to the model we want. To the point, I think the trait solver ought to have the job of "breaking down" higher-ranked region obligation like ``!1: '2` into into region obligations that operate on things in the root universe, at which point they should be handed off to polonius. The leak check isn't *really* doing that -- these obligations are still handed to the region solver to process -- but if/when we do adopt that model, the decision to pass/fail would be happening in roughly this part of the code. This change had somewhat more side-effects than I anticipated. It seems like there are cases where the leak-check was not being enforced during method proving and trait selection. I haven't quite tracked this down but I think it ought to be documented, so that we know what precisely we are committing to. One surprising test was `issue-30786.rs`. The behavior there seems a bit "fishy" to me, but the problem is not related to the leak check change as far as I can tell, but more to do with the closure signature inference code and perhaps the associated type projection, which together seem to be conspiring to produce an unexpected signature. Nonetheless, it is an example of where changing the leak-check can have some unexpected consequences: we're now failing to resolve a method earlier than we were, which suggests we might change some method resolutions that would have been ambiguous to be successful. TODO: * figure out remainig test failures * add new coherence tests for the patterns we ARE disallowing --- src/librustc_infer/infer/higher_ranked/mod.rs | 18 +++- .../infer/region_constraints/leak_check.rs | 1 + .../traits/coherence.rs | 10 +- .../traits/project.rs | 6 +- .../traits/select/mod.rs | 12 ++- .../associated-types-eq-hr.stderr | 2 +- ...project-fn-ret-invariant.krisskross.stderr | 30 +++--- .../cache/project-fn-ret-invariant.ok.stderr | 6 +- .../project-fn-ret-invariant.oneuse.stderr | 14 +-- .../cache/project-fn-ret-invariant.rs | 41 +++---- .../project-fn-ret-invariant.transmute.stderr | 26 ++--- .../expect-fn-supply-fn.rs | 17 +-- .../expect-fn-supply-fn.stderr | 71 +++++------- src/test/ui/closures/issue-41366.rs | 3 +- src/test/ui/closures/issue-41366.stderr | 21 ++-- .../ui/generator/resume-arg-late-bound.rs | 3 +- .../ui/generator/resume-arg-late-bound.stderr | 28 +++-- ...pe.bound_a_b_ret_a_vs_bound_a_ret_a.stderr | 2 +- .../hr-subtype.bound_a_b_vs_bound_a.stderr | 23 ++-- .../hr-subtype.bound_a_vs_bound_a.stderr | 2 +- .../hr-subtype.bound_a_vs_bound_b.stderr | 2 +- .../hr-subtype.bound_a_vs_free_x.stderr | 2 +- ...-subtype.bound_co_a_b_vs_bound_co_a.stderr | 2 +- ...ubtype.bound_co_a_co_b_ret_contra_a.stderr | 2 +- ...hr-subtype.bound_co_a_vs_bound_co_b.stderr | 2 +- ...pe.bound_contra_a_contra_b_ret_co_a.stderr | 23 ++-- ...ubtype.bound_inv_a_b_vs_bound_inv_a.stderr | 2 +- ...-subtype.bound_inv_a_vs_bound_inv_b.stderr | 2 +- .../hr-subtype.free_x_vs_free_x.stderr | 2 +- src/test/ui/hr-subtype/hr-subtype.rs | 4 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 4 +- src/test/ui/hrtb/issue-30786.migrate.stderr | 50 ++++++--- src/test/ui/hrtb/issue-30786.nll.stderr | 99 ++++++++--------- src/test/ui/hrtb/issue-30786.rs | 102 +++++++++++------- src/test/ui/issues/issue-40000.stderr | 6 +- src/test/ui/issues/issue-43623.rs | 7 +- src/test/ui/issues/issue-43623.stderr | 29 ++--- src/test/ui/issues/issue-60283.rs | 8 +- src/test/ui/issues/issue-60283.stderr | 29 ++--- src/test/ui/lub-glb/old-lub-glb-hr.rs | 35 +++++- src/test/ui/lub-glb/old-lub-glb-hr.stderr | 10 +- src/test/ui/lub-glb/old-lub-glb-object.stderr | 25 +++-- .../closure-arg-type-mismatch.rs | 1 - .../closure-arg-type-mismatch.stderr | 14 +-- .../ui/mismatched_types/closure-mismatch.rs | 1 - .../mismatched_types/closure-mismatch.stderr | 18 +--- ...ons-fn-subtyping-return-static-fail.stderr | 4 +- ...lifetime-bounds-on-fns-where-clause.stderr | 6 +- ...lifetime-bounds-on-fns-where-clause.stderr | 6 +- .../regions-lifetime-bounds-on-fns.stderr | 6 +- src/test/ui/rfc1623.rs | 7 +- src/test/ui/rfc1623.stderr | 25 ++--- .../issue-57611-trait-alias.rs | 2 +- .../issue-57611-trait-alias.stderr | 16 +-- .../unboxed-closures-unsafe-extern-fn.rs | 22 ++-- .../unboxed-closures-unsafe-extern-fn.stderr | 44 ++------ .../unboxed-closures-wrong-abi.rs | 22 ++-- .../unboxed-closures-wrong-abi.stderr | 44 ++------ ...boxed-closures-wrong-arg-type-extern-fn.rs | 22 ++-- ...d-closures-wrong-arg-type-extern-fn.stderr | 44 ++------ 60 files changed, 511 insertions(+), 576 deletions(-) diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs index b94221785ae75..b6251e34008a3 100644 --- a/src/librustc_infer/infer/higher_ranked/mod.rs +++ b/src/librustc_infer/infer/higher_ranked/mod.rs @@ -30,7 +30,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { let span = self.trace.cause.span; - self.infcx.commit_if_ok(|snapshot| { + self.infcx.commit_if_ok(|_| { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b); @@ -48,8 +48,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // Compare types now that bound regions have been replaced. let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - self.infcx.leak_check(!a_is_expected, snapshot)?; - debug!("higher_ranked_sub: OK result={:?}", result); Ok(ty::Binder::bind(result)) @@ -75,7 +73,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let next_universe = self.create_next_universe(); + // Figure out what the next universe will be, but don't actually create + // it until after we've done the substitution (in particular there may + // be no bound variables). This is a performance optimization, since the + // leak check for example can be skipped if no new universes are created + // (i.e., if there are no placeholders). + let next_universe = self.universe().next_universe(); let fld_r = |br| { self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { @@ -103,6 +106,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c); + // If there were higher-ranked regions to replace, then actually create + // the next universe (this avoids needlessly creating universes). + if !map.is_empty() { + let n_u = self.create_next_universe(); + assert_eq!(n_u, next_universe); + } + debug!( "replace_bound_vars_with_placeholders(\ next_universe={:?}, \ diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index f3b78909b42d8..32e708bf52b32 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -286,6 +286,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { placeholder: ty::PlaceholderRegion, other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { + debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); if self.overly_polymorphic { return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region); } else { diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs index 706cbf058b713..3ec7fe2bf25c6 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/src/librustc_trait_selection/traits/coherence.rs @@ -120,12 +120,13 @@ fn overlap<'cx, 'tcx>( debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, a_def_id, b_def_id, snapshot) + overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot) }) } fn overlap_within_probe( selcx: &mut SelectionContext<'cx, 'tcx>, + skip_leak_check: SkipLeakCheck, a_def_id: DefId, b_def_id: DefId, snapshot: &CombinedSnapshot<'_, 'tcx>, @@ -180,6 +181,13 @@ fn overlap_within_probe( return None; } + if !skip_leak_check.is_yes() { + if let Err(_) = infcx.leak_check(true, snapshot) { + debug!("overlap: leak check failed"); + return None; + } + } + let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 4bc58fbaadcda..ae255c22f9dca 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -298,11 +298,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { fn fold>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_vars_if_possible(value); - if !value.has_projections() { - value - } else { - value.fold_with(self) - } + if !value.has_projections() { value } else { value.fold_with(self) } } } diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index e90acbbce67ba..e5960e731033f 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -347,6 +347,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result { self.infcx.probe(|snapshot| -> Result { let result = op(self)?; + + match self.infcx.leak_check(true, snapshot) { + Ok(()) => {} + Err(_) => return Ok(EvaluatedToErr), + } + match self.infcx.region_constraints_added_in_snapshot(snapshot) { None => Ok(result), Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), @@ -2402,11 +2408,7 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { } fn depth(&self) -> usize { - if let Some(head) = self.head { - head.depth - } else { - 0 - } + if let Some(head) = self.head { head.depth } else { 0 } } } diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 50f1d07142f8c..315d180844d7a 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -74,7 +74,7 @@ LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> | ------------- required by this bound in `tuple_two` ... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:107:18 diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr index 5009e0868a7d4..9462121bdf203 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr @@ -1,23 +1,23 @@ error[E0623]: lifetime mismatch - --> $DIR/project-fn-ret-invariant.rs:53:21 + --> $DIR/project-fn-ret-invariant.rs:54:22 | -LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -------- -------------------- - | | - | this parameter and the return type are declared with different lifetimes... -LL | let a = bar(foo, y); - | ^ ...but data from `x` is returned here +LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -------- -------------------- + | | + | this parameter and the return type are declared with different lifetimes... +LL | let a = bar(foo, y); + | ^ ...but data from `x` is returned here error[E0623]: lifetime mismatch - --> $DIR/project-fn-ret-invariant.rs:54:21 + --> $DIR/project-fn-ret-invariant.rs:56:9 | -LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -------- -------------------- - | | - | this parameter and the return type are declared with different lifetimes... -LL | let a = bar(foo, y); -LL | let b = bar(foo, x); - | ^ ...but data from `y` is returned here +LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -------- -------------------- + | | + | this parameter and the return type are declared with different lifetimes... +... +LL | (a, b) + | ^ ...but data from `x` is returned here error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr index 8f445acf2b98c..2156ecb17393f 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr @@ -1,8 +1,8 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/project-fn-ret-invariant.rs:59:1 + --> $DIR/project-fn-ret-invariant.rs:60:1 | -LL | fn main() { } - | ^^^^^^^^^^^^^ +LL | fn main() {} + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr index 65d16440ac9b0..64b5722390858 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr @@ -1,13 +1,13 @@ error[E0623]: lifetime mismatch - --> $DIR/project-fn-ret-invariant.rs:39:19 + --> $DIR/project-fn-ret-invariant.rs:40:20 | -LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -------- -------------------- - | | - | this parameter and the return type are declared with different lifetimes... +LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -------- -------------------- + | | + | this parameter and the return type are declared with different lifetimes... ... -LL | let b = bar(f, y); - | ^ ...but data from `x` is returned here +LL | let b = bar(f, y); + | ^ ...but data from `x` is returned here error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs index 23d873212ed1e..0034d796826de 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs @@ -1,60 +1,61 @@ #![feature(unboxed_closures)] #![feature(rustc_attrs)] - // Test for projection cache. We should be able to project distinct // lifetimes from `foo` as we reinstantiate it multiple times, but not // if we do it just once. In this variant, the region `'a` is used in // an invariant position, which affects the results. // revisions: ok oneuse transmute krisskross - #![allow(dead_code, unused_variables)] use std::marker::PhantomData; struct Type<'a> { // Invariant - data: PhantomData &'a u32> + data: PhantomData &'a u32>, } -fn foo<'a>() -> Type<'a> { loop { } } +fn foo<'a>() -> Type<'a> { + loop {} +} fn bar(t: T, x: T::Output) -> T::Output - where T: FnOnce<()> +where + T: FnOnce<()>, { t() } #[cfg(ok)] // two instantiations: OK -fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { +fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { let a = bar(foo, x); let b = bar(foo, y); (a, b) } #[cfg(oneuse)] // one instantiation: BAD -fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - let f = foo; // <-- No consistent type can be inferred for `f` here. - let a = bar(f, x); - let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623] - (a, b) +fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + let f = foo; // <-- No consistent type can be inferred for `f` here. + let a = bar(f, x); + let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623] + (a, b) } #[cfg(transmute)] // one instantiations: BAD -fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { - // Cannot instantiate `foo` with any lifetime other than `'a`, - // since it is provided as input. +fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { + // Cannot instantiate `foo` with any lifetime other than `'a`, + // since it is provided as input. - bar(foo, x) //[transmute]~ ERROR E0495 + bar(foo, x) //[transmute]~ ERROR E0495 } #[cfg(krisskross)] // two instantiations, mixing and matching: BAD -fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - let a = bar(foo, y); //[krisskross]~ ERROR E0623 - let b = bar(foo, x); //[krisskross]~ ERROR E0623 - (a, b) +fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + let a = bar(foo, y); //[krisskross]~ ERROR E0623 + let b = bar(foo, x); + (a, b) //[krisskross]~ ERROR E0623 } #[rustc_error] -fn main() { } +fn main() {} //[ok]~^ ERROR fatal error triggered by #[rustc_error] diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 0a05fc6bb8286..ef57f9e0bc480 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,27 +1,27 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/project-fn-ret-invariant.rs:48:4 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements + --> $DIR/project-fn-ret-invariant.rs:49:9 | -LL | bar(foo, x) - | ^^^^^^^^^^^ +LL | bar(foo, x) + | ^^^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8... - --> $DIR/project-fn-ret-invariant.rs:44:8 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8... + --> $DIR/project-fn-ret-invariant.rs:45:8 | -LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { +LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | ^^ note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:48:13 + --> $DIR/project-fn-ret-invariant.rs:49:14 | -LL | bar(foo, x) - | ^ +LL | bar(foo, x) + | ^ = note: expected `Type<'_>` found `Type<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the expression is assignable - --> $DIR/project-fn-ret-invariant.rs:48:4 + --> $DIR/project-fn-ret-invariant.rs:49:5 | -LL | bar(foo, x) - | ^^^^^^^^^^^ +LL | bar(foo, x) + | ^^^^^^^^^^^ = note: expected `Type<'static>` found `Type<'_>` diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs index a4e43da91baf8..c81c40c18b45b 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs @@ -1,10 +1,12 @@ fn with_closure_expecting_fn_with_free_region(_: F) - where F: for<'a> FnOnce(fn(&'a u32), &i32) +where + F: for<'a> FnOnce(fn(&'a u32), &i32), { } fn with_closure_expecting_fn_with_bound_region(_: F) - where F: FnOnce(fn(&u32), &i32) +where + F: FnOnce(fn(&u32), &i32), { } @@ -28,14 +30,14 @@ fn expect_free_supply_bound() { // Here, we are given a function whose region is bound at closure level, // but we expect one bound in the argument. Error results. with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - //~^ ERROR type mismatch + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) { // Here, we are given a `fn(&u32)` but we expect a `fn(&'x // u32)`. In principle, this could be ok, but we demand equality. with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - //~^ ERROR type mismatch + //~^ ERROR mismatched types } fn expect_bound_supply_free_from_closure() { @@ -44,7 +46,7 @@ fn expect_bound_supply_free_from_closure() { // the argument level. type Foo<'a> = fn(&'a u32); with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - //~^ ERROR type mismatch + //~^ ERROR mismatched types }); } @@ -52,8 +54,7 @@ fn expect_bound_supply_bound<'x>(x: &'x u32) { // No error in this case. The supplied type supplies the bound // regions, and hence we are able to figure out the type of `y` // from the expected type - with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| { - }); + with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {}); } -fn main() { } +fn main() {} diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index fae41c4114abc..0de15dfa7357d 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -1,81 +1,68 @@ error[E0308]: mismatched types - --> $DIR/expect-fn-supply-fn.rs:14:52 + --> $DIR/expect-fn-supply-fn.rs:16:52 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&u32)` found fn pointer `fn(&'x u32)` -note: the anonymous lifetime #2 defined on the body at 14:48... - --> $DIR/expect-fn-supply-fn.rs:14:48 +note: the anonymous lifetime #2 defined on the body at 16:48... + --> $DIR/expect-fn-supply-fn.rs:16:48 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36 - --> $DIR/expect-fn-supply-fn.rs:11:36 +note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36 + --> $DIR/expect-fn-supply-fn.rs:13:36 | LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { | ^^ error[E0308]: mismatched types - --> $DIR/expect-fn-supply-fn.rs:14:52 + --> $DIR/expect-fn-supply-fn.rs:16:52 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&u32)` found fn pointer `fn(&'x u32)` -note: the lifetime `'x` as defined on the function body at 11:36... - --> $DIR/expect-fn-supply-fn.rs:11:36 +note: the lifetime `'x` as defined on the function body at 13:36... + --> $DIR/expect-fn-supply-fn.rs:13:36 | LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { | ^^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48 - --> $DIR/expect-fn-supply-fn.rs:14:48 +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48 + --> $DIR/expect-fn-supply-fn.rs:16:48 | LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:30:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:32:52 | -LL | fn with_closure_expecting_fn_with_free_region(_: F) - | ------------------------------------------ required by a bound in this -LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) - | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` -... LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `fn(fn(&'a u32), &i32) -> _` + | ^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `fn(&u32)` + found fn pointer `for<'r> fn(&'r u32)` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:37:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:39:53 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` -... LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^^^^^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'r> fn(&'r u32)` + found fn pointer `fn(&'x u32)` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:46:5 +error[E0308]: mismatched types + --> $DIR/expect-fn-supply-fn.rs:48:53 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` -... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^^^^^^^ one type is more general than the other + | + = note: expected fn pointer `for<'r> fn(&'r u32)` + found fn pointer `fn(&u32)` error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0631. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs index 5cae0e76d1acb..af1e37ba867de 100644 --- a/src/test/ui/closures/issue-41366.rs +++ b/src/test/ui/closures/issue-41366.rs @@ -7,7 +7,6 @@ impl<'g> T<'g> for u32 { } fn main() { - (&|_|()) as &dyn for<'x> Fn(>::V); + (&|_| ()) as &dyn for<'x> Fn(>::V); //~^ ERROR: type mismatch in closure arguments - //~| ERROR: type mismatch resolving } diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr index 2f2871e9f0e90..9c4b7d529ef4d 100644 --- a/src/test/ui/closures/issue-41366.stderr +++ b/src/test/ui/closures/issue-41366.stderr @@ -1,23 +1,14 @@ error[E0631]: type mismatch in closure arguments --> $DIR/issue-41366.rs:10:5 | -LL | (&|_|()) as &dyn for<'x> Fn(>::V); - | ^^-----^ +LL | (&|_| ()) as &dyn for<'x> Fn(>::V); + | ^^------^ | | | - | | found signature of `fn(_) -> _` - | expected signature of `for<'x> fn(>::V) -> _` + | | found signature of `fn(u16) -> _` + | expected signature of `fn(>::V) -> _` | = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` -error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(>::V,)>>::Output == ()` - --> $DIR/issue-41366.rs:10:5 - | -LL | (&|_|()) as &dyn for<'x> Fn(>::V); - | ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | - = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/generator/resume-arg-late-bound.rs b/src/test/ui/generator/resume-arg-late-bound.rs index 87b1f1a065bc8..a8f657eaabe47 100644 --- a/src/test/ui/generator/resume-arg-late-bound.rs +++ b/src/test/ui/generator/resume-arg-late-bound.rs @@ -13,5 +13,6 @@ fn main() { *arg = true; }; test(gen); - //~^ ERROR type mismatch in function arguments + //~^ ERROR mismatched types + //~| ERROR mismatched types } diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr index ffa440daed8c4..c379d9eae8ecd 100644 --- a/src/test/ui/generator/resume-arg-late-bound.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.stderr @@ -1,15 +1,21 @@ -error[E0631]: type mismatch in function arguments - --> $DIR/resume-arg-late-bound.rs:15:10 +error[E0308]: mismatched types + --> $DIR/resume-arg-late-bound.rs:15:5 | -LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {} - | ------------------------------- required by this bound in `test` -... LL | test(gen); - | ^^^ - | | - | expected signature of `for<'a> fn(&'a mut bool) -> _` - | found signature of `fn(&mut bool) -> _` + | ^^^^ one type is more general than the other + | + = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` + found type `std::ops::Generator<&mut bool>` + +error[E0308]: mismatched types + --> $DIR/resume-arg-late-bound.rs:15:5 + | +LL | test(gen); + | ^^^^ one type is more general than the other + | + = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` + found type `std::ops::Generator<&mut bool>` -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0631`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index 1da224a3e85e0..92a85825030c2 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr index 880a8c7be8305..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:45:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:102:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), -LL | | for<'a> fn(&'a u32, &'a u32)) } - | |__________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(&'a u32, &'b u32)>` - found enum `std::option::Option fn(&'a u32, &'a u32)>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index d2abcc4a66091..98f5bff732762 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr index e1a16f5149cc6..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr @@ -1,17 +1,14 @@ -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:45:26 +error: fatal error triggered by #[rustc_error] + --> $DIR/hr-subtype.rs:102:1 | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a -... -LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, -LL | | for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } - | |__________________________________________________- in this macro invocation - | - = note: expected enum `std::option::Option fn(Contra<'a>, Contra<'b>) -> Co<'a>>` - found enum `std::option::Option fn(Contra<'a>, Contra<'a>) -> Co<'a>>` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | +LL | | } + | |_^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 5fec1e9a92eae..100ba6ac27e25 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/hr-subtype.rs:45:26 | LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a + | ^^^^^^^^^^^ one type is more general than the other ... LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr index 0cc30e479c7b9..948375566104b 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/hr-subtype.rs:104:1 + --> $DIR/hr-subtype.rs:102:1 | LL | / fn main() { LL | | diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs index 9e9c2ce9c61d7..ad9500eedca93 100644 --- a/src/test/ui/hr-subtype/hr-subtype.rs +++ b/src/test/ui/hr-subtype/hr-subtype.rs @@ -48,8 +48,6 @@ macro_rules! check { //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR - //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types - //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^ ERROR } }; } @@ -109,4 +107,6 @@ fn main() { //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error] //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR + //[bound_a_b_vs_bound_a]~^^^^^^^^ ERROR + //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 328e98657effb..9914783d9767d 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/hrtb-exists-forall-fn.rs:17:34 | LL | let _: for<'b> fn(&'b u32) = foo(); - | ------------------- ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b - | | - | expected due to this + | ^^^^^ one type is more general than the other | = note: expected fn pointer `for<'b> fn(&'b u32)` found fn pointer `fn(&u32)` diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr index c0e3fd3cf4679..90a7cadca41b7 100644 --- a/src/test/ui/hrtb/issue-30786.migrate.stderr +++ b/src/test/ui/hrtb/issue-30786.migrate.stderr @@ -1,17 +1,43 @@ -error: implementation of `Stream` is not general enough - --> $DIR/issue-30786.rs:108:22 +error[E0599]: no method named `filterx` found for struct `Map` in the current scope + --> $DIR/issue-30786.rs:128:22 | -LL | / pub trait Stream { -LL | | type Item; -LL | | fn next(self) -> Option; -LL | | } - | |_- trait `Stream` defined here +LL | pub struct Map { + | -------------------- + | | + | method `filterx` not found for this + | doesn't satisfy `_: StreamExt` ... -LL | let map = source.map(|x: &_| x); - | ^^^ implementation of `Stream` is not general enough +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^ method not found in `Map` | - = note: `Stream` would have to be implemented for the type `&'0 mut Map`, for any lifetime `'0`... - = note: ...but `Stream` is actually implemented for the type `&'1 mut Map`, for some specific lifetime `'1` + = note: the method `filterx` exists but the following trait bounds were not satisfied: + `&'a mut Map: Stream` + which is required by `Map: StreamExt` + `&'a mut &Map: Stream` + which is required by `&Map: StreamExt` + `&'a mut &mut Map: Stream` + which is required by `&mut Map: StreamExt` -error: aborting due to previous error +error[E0599]: no method named `countx` found for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope + --> $DIR/issue-30786.rs:141:24 + | +LL | pub struct Filter { + | ----------------------- + | | + | method `countx` not found for this + | doesn't satisfy `_: StreamExt` +... +LL | let count = filter.countx(); + | ^^^^^^ method not found in `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` + | + = note: the method `countx` exists but the following trait bounds were not satisfied: + `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `&Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `&mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr index c736c5479f848..90a7cadca41b7 100644 --- a/src/test/ui/hrtb/issue-30786.nll.stderr +++ b/src/test/ui/hrtb/issue-30786.nll.stderr @@ -1,56 +1,43 @@ -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:108:15 - | -LL | let map = source.map(|x: &_| x); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:114:18 - | -LL | let filter = map.filter(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:114:18 - | -LL | let filter = map.filter(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:114:18 - | -LL | let filter = map.filter(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:114:18 - | -LL | let filter = map.filter(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:119:17 - | -LL | let count = filter.count(); // Assert that we still have a valid stream. - | ^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:119:17 - | -LL | let count = filter.count(); // Assert that we still have a valid stream. - | ^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:119:17 - | -LL | let count = filter.count(); // Assert that we still have a valid stream. - | ^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/issue-30786.rs:119:17 - | -LL | let count = filter.count(); // Assert that we still have a valid stream. - | ^^^^^^^^^^^^^^ - -error: aborting due to 9 previous errors - +error[E0599]: no method named `filterx` found for struct `Map` in the current scope + --> $DIR/issue-30786.rs:128:22 + | +LL | pub struct Map { + | -------------------- + | | + | method `filterx` not found for this + | doesn't satisfy `_: StreamExt` +... +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^ method not found in `Map` + | + = note: the method `filterx` exists but the following trait bounds were not satisfied: + `&'a mut Map: Stream` + which is required by `Map: StreamExt` + `&'a mut &Map: Stream` + which is required by `&Map: StreamExt` + `&'a mut &mut Map: Stream` + which is required by `&mut Map: StreamExt` + +error[E0599]: no method named `countx` found for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope + --> $DIR/issue-30786.rs:141:24 + | +LL | pub struct Filter { + | ----------------------- + | | + | method `countx` not found for this + | doesn't satisfy `_: StreamExt` +... +LL | let count = filter.countx(); + | ^^^^^^ method not found in `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` + | + = note: the method `countx` exists but the following trait bounds were not satisfied: + `&'a mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + `&'a mut &Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `&Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + `&'a mut &mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream` + which is required by `&mut Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs index c656f84306536..8ce5c090b543e 100644 --- a/src/test/ui/hrtb/issue-30786.rs +++ b/src/test/ui/hrtb/issue-30786.rs @@ -16,7 +16,7 @@ //[nll]compile-flags: -Z borrowck=mir -pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here +pub trait Stream { type Item; fn next(self) -> Option; } @@ -37,8 +37,9 @@ pub struct Map { } impl<'a, A, F, T> Stream for &'a mut Map -where &'a mut A: Stream, - F: FnMut(<&'a mut A as Stream>::Item) -> T, +where + &'a mut A: Stream, + F: FnMut(<&'a mut A as Stream>::Item) -> T, { type Item = T; fn next(self) -> Option { @@ -55,8 +56,9 @@ pub struct Filter { } impl<'a, A, F, T> Stream for &'a mut Filter -where for<'b> &'b mut A: Stream, // <---- BAD - F: FnMut(&T) -> bool, +where + for<'b> &'b mut A: Stream, // <---- BAD + F: FnMut(&T) -> bool, { type Item = <&'a mut A as Stream>::Item; fn next(self) -> Option { @@ -69,29 +71,29 @@ where for<'b> &'b mut A: Stream, // <---- BAD } } -pub trait StreamExt where for<'b> &'b mut Self: Stream { - fn map(self, func: F) -> Map - where Self: Sized, - for<'a> &'a mut Map: Stream, +pub trait StreamExt +where + for<'b> &'b mut Self: Stream, +{ + fn mapx(self, func: F) -> Map + where + Self: Sized, + for<'a> &'a mut Map: Stream, { - Map { - func: func, - stream: self, - } + Map { func: func, stream: self } } - fn filter(self, func: F) -> Filter - where Self: Sized, - for<'a> &'a mut Filter: Stream, + fn filterx(self, func: F) -> Filter + where + Self: Sized, + for<'a> &'a mut Filter: Stream, { - Filter { - func: func, - stream: self, - } + Filter { func: func, stream: self } } - fn count(mut self) -> usize - where Self: Sized, + fn countx(mut self) -> usize + where + Self: Sized, { let mut count = 0; while let Some(_) = self.next() { @@ -101,24 +103,44 @@ pub trait StreamExt where for<'b> &'b mut Self: Stream { } } -impl StreamExt for T where for<'a> &'a mut T: Stream { } +impl StreamExt for T where for<'a> &'a mut T: Stream {} -fn main() { +fn identity(x: &T) -> &T { + x +} + +fn variant1() { let source = Repeat(10); - let map = source.map(|x: &_| x); - //[nll]~^ ERROR higher-ranked subtype error - //[migrate]~^^ ERROR implementation of `Stream` is not general enough - //[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map - //[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1 - //[migrate]~| NOTE implementation of `Stream` is not general enough - let filter = map.filter(|x: &_| true); - //[nll]~^ ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error - let count = filter.count(); // Assert that we still have a valid stream. - //[nll]~^ ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error - //[nll]~| ERROR higher-ranked subtype error + + // Here, the call to `mapx` returns a type `T` to which `StreamExt` + // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold. + // + // More concretely, the type `T` is `Map`, and + // the where clause doesn't hold because the signature of the + // closure gets inferred to a signature like `|&'_ Stream| -> &'_` + // for some specific `'_`, rather than a more generic + // signature. + // + // Why *exactly* we opt for this signature is a bit unclear to me, + // we deduce it somehow from a reuqirement that `Map: Stream` I + // guess. + let map = source.mapx(|x: &_| x); + let filter = map.filterx(|x: &_| true); + //[migrate]~^ ERROR no method named `filterx` + //[nll]~^^ ERROR no method named `filterx` } + +fn variant2() { + let source = Repeat(10); + + // Here, we use a function, which is not subject to the vagaries + // of closure signature inference. In this case, we get the error + // on `countx` as, I think, the test originally expected. + let map = source.mapx(identity); + let filter = map.filterx(|x: &_| true); + let count = filter.countx(); + //[migrate]~^ ERROR no method named `countx` + //[nll]~^^ ERROR no method named `countx` +} + +fn main() {} diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 983fdb13083a1..3eb3482ac910e 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-40000.rs:6:9 | LL | foo(bar); - | ^^^ expected concrete lifetime, found bound lifetime parameter + | ^^^ one type is more general than the other | - = note: expected struct `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>` - found struct `std::boxed::Box` + = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)` + found trait object `dyn std::ops::Fn(&i32)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs index b259e9e269d06..99cae46fd9cf2 100644 --- a/src/test/ui/issues/issue-43623.rs +++ b/src/test/ui/issues/issue-43623.rs @@ -9,11 +9,12 @@ impl<'a> Trait<'a> for Type { } pub fn break_me(f: F) -where T: for<'b> Trait<'b>, - F: for<'b> FnMut(>::Assoc) { +where + T: for<'b> Trait<'b>, + F: for<'b> FnMut(>::Assoc), +{ break_me::; //~^ ERROR: type mismatch in function arguments - //~| ERROR: type mismatch resolving } fn main() {} diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr index 99fb2a1f5d030..80aca482b3d29 100644 --- a/src/test/ui/issues/issue-43623.stderr +++ b/src/test/ui/issues/issue-43623.stderr @@ -1,29 +1,18 @@ error[E0631]: type mismatch in function arguments - --> $DIR/issue-43623.rs:14:5 + --> $DIR/issue-43623.rs:16:5 | LL | pub fn break_me(f: F) | -------- required by a bound in this -LL | where T: for<'b> Trait<'b>, -LL | F: for<'b> FnMut(>::Assoc) { - | -------------------------------------- required by this bound in `break_me` +... +LL | F: for<'b> FnMut(>::Assoc), + | ------------------------------ required by this bound in `break_me` +LL | { LL | break_me::; | ^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected signature of `for<'b> fn(>::Assoc) -> _` - | found signature of `fn(_) -> _` + | expected signature of `fn(>::Assoc) -> _` + | found signature of `fn(()) -> _` -error[E0271]: type mismatch resolving `for<'b> >::Assoc,)>>::Output == ()` - --> $DIR/issue-43623.rs:14:5 - | -LL | pub fn break_me(f: F) - | -------- required by a bound in this -LL | where T: for<'b> Trait<'b>, -LL | F: for<'b> FnMut(>::Assoc) { - | ------------------------------ required by this bound in `break_me` -LL | break_me::; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs index e5a9caa32fae7..9c2b2dc9f4dae 100644 --- a/src/test/ui/issues/issue-60283.rs +++ b/src/test/ui/issues/issue-60283.rs @@ -7,11 +7,13 @@ impl<'a> Trait<'a> for () { } pub fn foo(_: T, _: F) -where T: for<'a> Trait<'a>, - F: for<'a> FnMut(>::Item) {} +where + T: for<'a> Trait<'a>, + F: for<'a> FnMut(>::Item), +{ +} fn main() { foo((), drop) //~^ ERROR type mismatch in function arguments - //~| ERROR type mismatch resolving } diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr index e74a34e247a67..ad679bfa22063 100644 --- a/src/test/ui/issues/issue-60283.stderr +++ b/src/test/ui/issues/issue-60283.stderr @@ -1,31 +1,18 @@ error[E0631]: type mismatch in function arguments - --> $DIR/issue-60283.rs:14:13 + --> $DIR/issue-60283.rs:17:13 | LL | pub fn foo(_: T, _: F) | --- required by a bound in this -LL | where T: for<'a> Trait<'a>, -LL | F: for<'a> FnMut(>::Item) {} - | ------------------------------------- required by this bound in `foo` +... +LL | F: for<'a> FnMut(>::Item), + | ----------------------------- required by this bound in `foo` ... LL | foo((), drop) | ^^^^ | | - | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` - | found signature of `fn(_) -> _` - -error[E0271]: type mismatch resolving `for<'a> } as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()` - --> $DIR/issue-60283.rs:14:5 - | -LL | pub fn foo(_: T, _: F) - | --- required by a bound in this -LL | where T: for<'a> Trait<'a>, -LL | F: for<'a> FnMut(>::Item) {} - | ----------------------------- required by this bound in `foo` -... -LL | foo((), drop) - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | expected signature of `fn(<() as Trait<'a>>::Item) -> _` + | found signature of `fn(()) -> _` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs index bc7b787cd65ac..5e24a99bcc331 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.rs +++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs @@ -3,21 +3,21 @@ // error. However, now that we handle subtyping correctly, we no // longer get an error, because we recognize these two types as // equivalent! -// -// Whoops -- now that we reinstituted the leak-check, we get an error -// again. fn foo( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { + // The two types above are actually equivalent. With the older + // leak check, though, we didn't consider them as equivalent, and + // hence we gave errors. But now we've fixed that. let z = match 22 { 0 => x, - _ => y, //~ ERROR `match` arms have incompatible types + _ => y, }; } -fn bar( +fn foo_cast( x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8), ) { @@ -28,5 +28,30 @@ fn bar( }; } +fn bar( + x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, + y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, +) { + // The two types above are not equivalent. With the older LUB/GLB + // algorithm, this may have worked (I don't remember), but now it + // doesn't because we require equality. + let z = match 22 { + 0 => x, + _ => y, //~ ERROR `match` arms have incompatible types + }; +} + +fn bar_cast( + x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, + y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, +) { + // But we can *upcast* explicitly the type of `x` and figure + // things out: + let z = match 22 { + 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, + _ => y, + }; +} + fn main() { } diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr index 6d5d51174699f..f9ad4e5814eeb 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr @@ -1,17 +1,17 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/old-lub-glb-hr.rs:16:14 + --> $DIR/old-lub-glb-hr.rs:40:14 | LL | let z = match 22 { | _____________- LL | | 0 => x, - | | - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)` + | | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` LL | | _ => y, - | | ^ expected bound lifetime parameter, found concrete lifetime + | | ^ one type is more general than the other LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)` - found fn pointer `for<'a> fn(&'a u8, &'a u8)` + = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` error: aborting due to previous error diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 65c797f6b19d7..81f07df3f50bf 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,18 +1,25 @@ -error[E0308]: `match` arms have incompatible types - --> $DIR/old-lub-glb-object.rs:12:14 +error[E0308]: mismatched types + --> $DIR/old-lub-glb-object.rs:10:13 | LL | let z = match 22 { - | _____________- + | _____________^ LL | | 0 => x, - | | - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>` LL | | _ => y, - | | ^ expected bound lifetime parameter 'a, found concrete lifetime LL | | }; - | |_____- `match` arms have incompatible types + | |_____^ one type is more general than the other | - = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>` - found reference `&dyn for<'a> Foo<&'a u8, &'a u8>` + = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/old-lub-glb-object.rs:22:14 + | +LL | 0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>, + | ^ one type is more general than the other + | + = note: expected trait object `dyn for<'a> Foo<&'a u8, &'a u8>` + found trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs index 521bd3695dfe5..fd4463b63e10e 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -8,5 +8,4 @@ fn main() { fn baz(_: F) {} fn _test<'a>(f: fn(*mut &'a u32)) { baz(f); //~ ERROR type mismatch - //~| ERROR type mismatch } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 69a4b458ebf50..503899af33ed7 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -22,18 +22,6 @@ LL | a.iter().map(|_: (u16, u16)| 45); | | | expected signature of `fn(&(u32, u32)) -> _` -error[E0631]: type mismatch in function arguments - --> $DIR/closure-arg-type-mismatch.rs:10:9 - | -LL | fn baz(_: F) {} - | ------------- required by this bound in `baz` -LL | fn _test<'a>(f: fn(*mut &'a u32)) { -LL | baz(f); - | ^ - | | - | expected signature of `for<'r> fn(*mut &'r u32) -> _` - | found signature of `fn(*mut &'a u32) -> _` - error[E0271]: type mismatch resolving `for<'r> >::Output == ()` --> $DIR/closure-arg-type-mismatch.rs:10:5 | @@ -43,7 +31,7 @@ LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); | ^^^ expected bound lifetime parameter, found concrete lifetime -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0271, E0631. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs index 40a4641fe7196..cb2cb228c62e1 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -6,5 +6,4 @@ fn baz(_: T) {} fn main() { baz(|_| ()); //~ ERROR type mismatch - //~^ ERROR type mismatch } diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 389b21574465a..7fab9490ac93f 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -9,20 +9,6 @@ LL | baz(|_| ()); | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` -error[E0631]: type mismatch in closure arguments - --> $DIR/closure-mismatch.rs:8:5 - | -LL | fn baz(_: T) {} - | --- required by this bound in `baz` -... -LL | baz(|_| ()); - | ^^^ ------ found signature of `fn(_) -> _` - | | - | expected signature of `for<'r> fn(&'r ()) -> _` - | - = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 6d75ace3c4698..c9ce936c7d43f 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 | LL | want_G(baz); - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx + | ^^^ one type is more general than the other | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S` - found fn item `for<'r> fn(&'r S) -> &'r S {baz}` + found fn pointer `for<'r> fn(&'r S) -> &'r S` error: aborting due to previous error diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr index 159d32b50b03c..b83e07663faba 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -20,12 +20,10 @@ error[E0308]: mismatched types --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 | LL | let _: fn(&mut &isize, &mut &isize) = a; - | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^ one type is more general than the other | = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr index dda6129e19536..c93f2890f1110 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -31,12 +31,10 @@ error[E0308]: mismatched types --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 | LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; - | ----------------------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^ one type is more general than the other | = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` - found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}` + found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr index 01f43aeebaf7c..2b2dd0dbbf250 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -20,12 +20,10 @@ error[E0308]: mismatched types --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 | LL | let _: fn(&mut &isize, &mut &isize) = a; - | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^ one type is more general than the other | = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` + found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)` error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index 55f5d0b94dcb0..0564d53b944e6 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -8,7 +8,6 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8); - struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, bar: &'x Bar<'z>, @@ -19,12 +18,12 @@ fn id(t: T) -> T { t } -static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types +static SOME_STRUCT: &SomeStruct = SomeStruct { + //~^ ERROR mismatched types foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, - //~^ ERROR type mismatch in function arguments - //~| ERROR type mismatch resolving + //~^ ERROR type mismatch resolving }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 75df99137179b..90dc7cbfa5521 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,46 +1,35 @@ error[E0308]: mismatched types - --> $DIR/rfc1623.rs:22:35 + --> $DIR/rfc1623.rs:21:35 | LL | static SOME_STRUCT: &SomeStruct = SomeStruct { | ___________________________________^ +LL | | LL | | foo: &Foo { bools: &[false, true] }, LL | | bar: &Bar { bools: &[true, true] }, LL | | f: &id, LL | | -LL | | LL | | }; | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct` | help: consider borrowing here | LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { +LL | LL | foo: &Foo { bools: &[false, true] }, LL | bar: &Bar { bools: &[true, true] }, LL | f: &id, -LL | LL | ... -error[E0631]: type mismatch in function arguments - --> $DIR/rfc1623.rs:25:8 - | -LL | fn id(t: T) -> T { - | ------------------- found signature of `fn(_) -> _` -... -LL | f: &id, - | ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _` - | - = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` - -error[E0271]: type mismatch resolving `for<'a, 'b> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` +error[E0271]: type mismatch resolving `for<'a, 'b> ) -> &Foo<'_> {id::<&Foo<'_>>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` --> $DIR/rfc1623.rs:25:8 | LL | f: &id, - | ^^^ expected bound lifetime parameter 'b, found concrete lifetime + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime | = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0308, E0631. +Some errors have detailed explanations: E0271, E0308. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 1c2051e7eaeeb..84111b1aef8d4 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -14,7 +14,7 @@ trait Foo { struct X; impl Foo for X { - type Bar = impl Baz; //~ ERROR type mismatch in closure arguments + type Bar = impl Baz; //~^ ERROR type mismatch resolving fn bar(&self) -> Self::Bar { diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index cc121ac89fb8d..3cb8abcdcfd17 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -1,14 +1,3 @@ -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-57611-trait-alias.rs:17:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _` -... -LL | |x| x - | ----- found signature of `fn(_) -> _` - | - = note: the return type of a function must have a statically known size - error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X` --> $DIR/issue-57611-trait-alias.rs:17:16 | @@ -17,7 +6,6 @@ LL | type Bar = impl Baz; | = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs index a6e26614a6a50..e2082d4f78e70 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs @@ -1,23 +1,29 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -use std::ops::{Fn,FnMut,FnOnce}; +use std::ops::{Fn, FnMut, FnOnce}; -unsafe fn square(x: &isize) -> isize { (*x) * (*x) } +unsafe fn square(x: &isize) -> isize { + (*x) * (*x) +} -fn call_itisize>(_: &F, _: isize) -> isize { 0 } -fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } -fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } +fn call_it isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once isize>(_: F, _: isize) -> isize { + 0 +} fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn c() { @@ -25,4 +31,4 @@ fn c() { //~^ ERROR E0277 } -fn main() { } +fn main() {} diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index b9ee9e460201a..b06f745e7c1f1 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -1,30 +1,19 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21 + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----------------- required by this bound in `call_it` +LL | fn call_it isize>(_: &F, _: isize) -> isize { + | ------------------- required by this bound in `call_it` ... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it` -... -LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` - error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25 + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | -------------------- required by this bound in `call_it_mut` +LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + | ---------------------- required by this bound in `call_it_mut` ... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` @@ -32,27 +21,16 @@ LL | let y = call_it_mut(&mut square, 22); = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_mut` -... -LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` - -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:26 + --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_once` +LL | fn call_it_once isize>(_: F, _: isize) -> isize { + | ----------------------- required by this bound in `call_it_once` ... LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs index dd3b1afc39f31..dd76c597d28ad 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs @@ -1,23 +1,29 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -use std::ops::{Fn,FnMut,FnOnce}; +use std::ops::{Fn, FnMut, FnOnce}; -extern "C" fn square(x: &isize) -> isize { (*x) * (*x) } +extern "C" fn square(x: &isize) -> isize { + (*x) * (*x) +} -fn call_itisize>(_: &F, _: isize) -> isize { 0 } -fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } -fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } +fn call_it isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once isize>(_: F, _: isize) -> isize { + 0 +} fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn c() { @@ -25,4 +31,4 @@ fn c() { //~^ ERROR E0277 } -fn main() { } +fn main() {} diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 654b626cf65cc..8f6945cda806c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -1,30 +1,19 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:12:21 + --> $DIR/unboxed-closures-wrong-abi.rs:20:21 | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----------------- required by this bound in `call_it` +LL | fn call_it isize>(_: &F, _: isize) -> isize { + | ------------------- required by this bound in `call_it` ... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:12:21 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it` -... -LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` - error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:18:25 + --> $DIR/unboxed-closures-wrong-abi.rs:25:25 | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | -------------------- required by this bound in `call_it_mut` +LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + | ---------------------- required by this bound in `call_it_mut` ... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` @@ -32,27 +21,16 @@ LL | let y = call_it_mut(&mut square, 22); = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:18:25 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_mut` -... -LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` - -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:24:26 + --> $DIR/unboxed-closures-wrong-abi.rs:30:26 | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_once` +LL | fn call_it_once isize>(_: F, _: isize) -> isize { + | ----------------------- required by this bound in `call_it_once` ... LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs index c689d79266187..02e8b7b47ae19 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -1,24 +1,30 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -use std::ops::{Fn,FnMut,FnOnce}; +use std::ops::{Fn, FnMut, FnOnce}; -unsafe fn square(x: isize) -> isize { x * x } +unsafe fn square(x: isize) -> isize { + x * x +} // note: argument type here is `isize`, not `&isize` -fn call_itisize>(_: &F, _: isize) -> isize { 0 } -fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } -fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } +fn call_it isize>(_: &F, _: isize) -> isize { + 0 +} +fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + 0 +} +fn call_it_once isize>(_: F, _: isize) -> isize { + 0 +} fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR expected } fn c() { @@ -26,4 +32,4 @@ fn c() { //~^ ERROR E0277 } -fn main() { } +fn main() {} diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 434c8a579f671..93a645b485ef0 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -1,30 +1,19 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21 + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----------------- required by this bound in `call_it` +LL | fn call_it isize>(_: &F, _: isize) -> isize { + | ------------------- required by this bound in `call_it` ... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it` -... -LL | let x = call_it(&square, 22); - | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` - error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25 + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | -------------------- required by this bound in `call_it_mut` +LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { + | ---------------------- required by this bound in `call_it_mut` ... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` @@ -32,27 +21,16 @@ LL | let y = call_it_mut(&mut square, 22); = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_mut` -... -LL | let y = call_it_mut(&mut square, 22); - | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` - -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:26 + --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ----- required by this bound in `call_it_once` +LL | fn call_it_once isize>(_: F, _: isize) -> isize { + | ----------------------- required by this bound in `call_it_once` ... LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From 1e00e1b6debce8270dd75e795458ba8becdffe1f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 May 2020 14:31:51 +0000 Subject: [PATCH 21/30] upcasting traits requires only that things become more general Revert the code that states that upcasting traits requires full equality and change to require that the source type is a subtype of the target type, as one would expect. As the comment states, this was an old bug that we didn't want to fix yet as it interacted poorly with the old leak-check. This fixes the old-lub-glb-object test, which was previously reporting too many errors (i.e., in the previous commit). --- .../traits/select/confirmation.rs | 16 +--------------- ...s_of_reborrow.SimplifyCfg-initial.after.mir | 4 ++-- src/test/ui/lub-glb/old-lub-glb-object.rs | 18 ++++++------------ src/test/ui/lub-glb/old-lub-glb-object.stderr | 14 +++----------- 4 files changed, 12 insertions(+), 40 deletions(-) diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index 50c04e8fc3452..4837acbd1dedc 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -612,24 +612,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. - // - // FIXME: This condition is arguably too strong -- it would - // suffice for the source trait to be a *subtype* of the target - // trait. In particular, changing from something like - // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be - // permitted. And, indeed, in the in commit - // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this - // condition was loosened. However, when the leak check was - // added back, using subtype here actually guides the coercion - // code in such a way that it accepts `old-lub-glb-object.rs`. - // This is probably a good thing, but I've modified this to `.eq` - // because I want to continue rejecting that test (as we have - // done for quite some time) before we are firmly comfortable - // with what our behavior should be there. -nikomatsakis let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(target, source_trait) // FIXME -- see below + .sup(target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); diff --git a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir index 9742530bd812f..aeb38f3f91068 100644 --- a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -12,7 +12,7 @@ | 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24 | 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24 | 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18 -| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25 +| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25 | 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20 | 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20 | 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28 @@ -22,7 +22,7 @@ | 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24 | 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24 | 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16 -| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23 +| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23 | 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18 | 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18 | 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26 diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs index 63bbae59991bc..39d351c235574 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.rs +++ b/src/test/ui/lub-glb/old-lub-glb-object.rs @@ -1,22 +1,17 @@ // Test that we give a note when the old LUB/GLB algorithm would have // succeeded but the new code (which is stricter) gives an error. -trait Foo { } +trait Foo {} -fn foo( - x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, - y: &dyn for<'a> Foo<&'a u8, &'a u8>, -) { +fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) { let z = match 22 { + //~^ ERROR mismatched types 0 => x, - _ => y, //~ ERROR `match` arms have incompatible types + _ => y, }; } -fn bar( - x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, - y: &dyn for<'a> Foo<&'a u8, &'a u8>, -) { +fn bar(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) { // Accepted with explicit case: let z = match 22 { 0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>, @@ -24,5 +19,4 @@ fn bar( }; } -fn main() { -} +fn main() {} diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr index 81f07df3f50bf..6eabe5eaeeeeb 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr @@ -1,8 +1,9 @@ error[E0308]: mismatched types - --> $DIR/old-lub-glb-object.rs:10:13 + --> $DIR/old-lub-glb-object.rs:7:13 | LL | let z = match 22 { | _____________^ +LL | | LL | | 0 => x, LL | | _ => y, LL | | }; @@ -11,15 +12,6 @@ LL | | }; = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` -error[E0308]: mismatched types - --> $DIR/old-lub-glb-object.rs:22:14 - | -LL | 0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>, - | ^ one type is more general than the other - | - = note: expected trait object `dyn for<'a> Foo<&'a u8, &'a u8>` - found trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. From 70cf33fccaac072a153f6e211aa907c83c465fef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 May 2020 17:48:07 +0000 Subject: [PATCH 22/30] remove snapshot calls from "match" operations during select Motivation: - we want to use leak-check sparingly, first off - these calls were essentially the same as doing the check during subtyping --- .../traits/select/candidate_assembly.rs | 10 +-- .../traits/select/confirmation.rs | 9 +- .../traits/select/mod.rs | 29 ++----- .../associated-types-eq-hr.rs | 35 ++++---- .../associated-types-eq-hr.stderr | 87 +++++++------------ src/test/ui/hrtb/hrtb-conflate-regions.stderr | 21 +++-- .../hrtb-exists-forall-trait-contravariant.rs | 2 +- ...b-exists-forall-trait-contravariant.stderr | 18 ++-- .../hrtb-exists-forall-trait-invariant.rs | 2 +- .../hrtb-exists-forall-trait-invariant.stderr | 18 ++-- src/test/ui/hrtb/hrtb-just-for-static.stderr | 41 +++++---- src/test/ui/hrtb/issue-46989.rs | 8 +- src/test/ui/hrtb/issue-46989.stderr | 15 ++-- src/test/ui/issues/issue-57362-2.stderr | 2 + src/test/ui/where-clauses/where-for-self-2.rs | 8 +- .../ui/where-clauses/where-for-self-2.stderr | 21 +++-- 16 files changed, 138 insertions(+), 188 deletions(-) diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs index 9045451056b19..4dab5814f7b7e 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs @@ -163,9 +163,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, } - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_definition_bounds(obligation, snapshot) - }); + let result = self + .infcx + .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); if result { candidates.vec.push(ProjectionCandidate); @@ -345,8 +345,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) { + self.infcx.probe(|_| { + if let Ok(_substs) = self.match_impl(impl_def_id, obligation) { candidates.vec.push(ImplCandidate(impl_def_id)); } }); diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index 4837acbd1dedc..834bf17227d2e 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -121,9 +121,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.commit_unconditionally(|snapshot| { - let result = - self.match_projection_obligation_against_definition_bounds(obligation, snapshot); + self.infcx.commit_unconditionally(|_| { + let result = self.match_projection_obligation_against_definition_bounds(obligation); assert!(result); }) } @@ -265,8 +264,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.commit_unconditionally(|snapshot| { - let substs = self.rematch_impl(impl_def_id, obligation, snapshot); + self.infcx.commit_unconditionally(|_| { + let substs = self.rematch_impl(impl_def_id, obligation); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); ensure_sufficient_stack(|| { diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index e5960e731033f..cff5efbfd0fd1 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -21,7 +21,7 @@ use super::{Normalized, ProjectionCacheKey}; use super::{ObligationCause, PredicateObligation, TraitObligation}; use super::{Overflow, SelectionError, Unimplemented}; -use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectionCacheKeyExt; use rustc_ast::attr; @@ -1268,7 +1268,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> bool { let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); let (placeholder_trait_predicate, _) = @@ -1299,12 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ty::PredicateKind::Trait(bound, _) = bound.kind() { let bound = bound.to_poly_trait_ref(); if self.infcx.probe(|_| { - self.match_projection( - obligation, - bound, - placeholder_trait_predicate.trait_ref, - snapshot, - ) + self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref) }) { return Some(bound); } @@ -1321,12 +1315,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => false, Some(bound) => { // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection( - obligation, - bound, - placeholder_trait_predicate.trait_ref, - snapshot, - ); + let result = + self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref); assert!(result); true @@ -1339,14 +1329,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_bound: ty::PolyTraitRef<'tcx>, placeholder_trait_ref: ty::TraitRef<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> bool { debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); self.infcx .at(&obligation.cause, obligation.param_env) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .is_ok() - && self.infcx.leak_check(false, snapshot).is_ok() } fn evaluate_where_clause<'o>( @@ -1811,9 +1799,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> Normalized<'tcx, SubstsRef<'tcx>> { - match self.match_impl(impl_def_id, obligation, snapshot) { + match self.match_impl(impl_def_id, obligation) { Ok(substs) => substs, Err(()) => { bug!( @@ -1829,7 +1816,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, impl_def_id: DefId, obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, ) -> Result>, ()> { let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); @@ -1872,11 +1858,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; nested_obligations.extend(obligations); - if let Err(e) = self.infcx.leak_check(false, snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - if !self.intercrate && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs index e6afa3f71c2f0..70e4be5929fb9 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.rs +++ b/src/test/ui/associated-types/associated-types-eq-hr.rs @@ -7,7 +7,7 @@ pub trait TheTrait { } struct IntStruct { - x: isize + x: isize, } impl<'a> TheTrait<&'a isize> for IntStruct { @@ -19,7 +19,7 @@ impl<'a> TheTrait<&'a isize> for IntStruct { } struct UintStruct { - x: isize + x: isize, } impl<'a> TheTrait<&'a isize> for UintStruct { @@ -30,8 +30,7 @@ impl<'a> TheTrait<&'a isize> for UintStruct { } } -struct Tuple { -} +struct Tuple {} impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple { type A = &'a isize; @@ -42,37 +41,43 @@ impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple { } fn foo() - where T : for<'x> TheTrait<&'x isize, A = &'x isize> +where + T: for<'x> TheTrait<&'x isize, A = &'x isize>, { // ok for IntStruct, but not UintStruct } fn bar() - where T : for<'x> TheTrait<&'x isize, A = &'x usize> +where + T: for<'x> TheTrait<&'x isize, A = &'x usize>, { // ok for UintStruct, but not IntStruct } fn tuple_one() - where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> +where + T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, { // not ok for tuple, two lifetimes and we pick first } fn tuple_two() - where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> +where + T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, { // not ok for tuple, two lifetimes and we pick second } fn tuple_three() - where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize> +where + T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>, { // ok for tuple } fn tuple_four() - where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> +where + T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>, { // not ok for tuple, two lifetimes, and lifetime matching is invariant } @@ -89,14 +94,12 @@ pub fn call_bar() { pub fn call_tuple_one() { tuple_one::(); - //~^ ERROR not satisfied - //~| ERROR type mismatch + //~^ ERROR type mismatch } pub fn call_tuple_two() { tuple_two::(); - //~^ ERROR not satisfied - //~| ERROR type mismatch + //~^ ERROR type mismatch } pub fn call_tuple_three() { @@ -105,7 +108,7 @@ pub fn call_tuple_three() { pub fn call_tuple_four() { tuple_four::(); - //~^ ERROR not satisfied + //~^ ERROR implementation of `TheTrait` is not general enough } -fn main() { } +fn main() {} diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 315d180844d7a..626cb55588fae 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -1,10 +1,11 @@ error[E0271]: type mismatch resolving `for<'x> >::A == &'x isize` - --> $DIR/associated-types-eq-hr.rs:82:5 + --> $DIR/associated-types-eq-hr.rs:87:5 | LL | fn foo() | --- required by a bound in this -LL | where T : for<'x> TheTrait<&'x isize, A = &'x isize> - | ------------- required by this bound in `foo` +LL | where +LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>, + | ------------- required by this bound in `foo` ... LL | foo::(); | ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize` @@ -13,12 +14,13 @@ LL | foo::(); found reference `&usize` error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` - --> $DIR/associated-types-eq-hr.rs:86:5 + --> $DIR/associated-types-eq-hr.rs:91:5 | LL | fn bar() | --- required by a bound in this -LL | where T : for<'x> TheTrait<&'x isize, A = &'x usize> - | ------------- required by this bound in `bar` +LL | where +LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>, + | ------------- required by this bound in `bar` ... LL | bar::(); | ^^^^^^^^^^^^^^^^ expected `usize`, found `isize` @@ -26,71 +28,46 @@ LL | bar::(); = note: expected reference `&usize` found reference `&isize` -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:91:17 - | -LL | fn tuple_one() - | --------- required by a bound in this -LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> - | ---------------------------------------------------------- required by this bound in `tuple_one` -... -LL | tuple_one::(); - | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > - error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` - --> $DIR/associated-types-eq-hr.rs:91:5 + --> $DIR/associated-types-eq-hr.rs:96:5 | LL | fn tuple_one() | --------- required by a bound in this -LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> - | ------------- required by this bound in `tuple_one` +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, + | ------------- required by this bound in `tuple_one` ... LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime - -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:97:17 - | -LL | fn tuple_two() - | --------- required by a bound in this -LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> - | ---------------------------------------------------------- required by this bound in `tuple_two` -... -LL | tuple_two::(); - | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` - --> $DIR/associated-types-eq-hr.rs:97:5 + --> $DIR/associated-types-eq-hr.rs:101:5 | LL | fn tuple_two() | --------- required by a bound in this -LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> - | ------------- required by this bound in `tuple_two` +LL | where +LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, + | ------------- required by this bound in `tuple_two` ... LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime -error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied - --> $DIR/associated-types-eq-hr.rs:107:18 +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:110:5 | -LL | fn tuple_four() - | ---------- required by a bound in this -LL | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> - | ------------------------------------------- required by this bound in `tuple_four` +LL | / pub trait TheTrait { +LL | | type A; +LL | | +LL | | fn get(&self, t: T) -> Self::A; +LL | | } + | |_- trait `TheTrait` defined here ... -LL | tuple_four::(); - | ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` +LL | tuple_four::(); + | ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough | - = help: the following implementations were found: - > + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 7250935ea296b..45573814d13c0 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,17 +1,16 @@ -error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied - --> $DIR/hrtb-conflate-regions.rs:27:22 +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-conflate-regions.rs:27:10 | -LL | fn want_foo2() - | --------- required by a bound in this -LL | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> - | -------------------------------------- required by this bound in `want_foo2` +LL | / trait Foo { +LL | | fn foo(&self, x: X) { } +LL | | } + | |_- trait `Foo` defined here ... -LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct` +LL | fn b() { want_foo2::(); } + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - > + = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs index 4c1d4d28a09b0..921061916fc95 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs @@ -32,5 +32,5 @@ fn main() { // NB. *However*, the reinstated leak-check gives an error here. foo::<()>(); - //~^ ERROR not satisfied + //~^ ERROR implementation of `Trait` is not general enough } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index 7a7285d3d76e0..fe8209d054c8a 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -1,18 +1,14 @@ -error[E0277]: the trait bound `(): Trait fn(&'b u32)>` is not satisfied - --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11 +error: implementation of `Trait` is not general enough + --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | -LL | fn foo() - | --- required by a bound in this -LL | where -LL | T: Trait fn(&'b u32)>, - | -------------------------- required by this bound in `foo` +LL | trait Trait {} + | ----------------- trait `Trait` defined here ... LL | foo::<()>(); - | ^^ the trait `Trait fn(&'b u32)>` is not implemented for `()` + | ^^^^^^^^^ implementation of `Trait` is not general enough | - = help: the following implementations were found: - <() as Trait> + = note: `()` must implement `Trait fn(&'b u32)>` + = note: ...but `()` actually implements `Trait`, for some specific lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs index 827a68beee8bd..b1b7ec6bcf1a5 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs @@ -25,5 +25,5 @@ fn main() { // yielding `fn(&!b u32)`, in a fresh universe U1 // - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`. - foo::<()>(); //~ ERROR not satisfied + foo::<()>(); //~ ERROR implementation of `Trait` is not general enough } diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index 9174ea4d8419d..720e2276d5343 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -1,18 +1,14 @@ -error[E0277]: the trait bound `(): Trait fn(std::cell::Cell<&'b u32>)>` is not satisfied - --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:11 +error: implementation of `Trait` is not general enough + --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | -LL | fn foo() - | --- required by a bound in this -LL | where -LL | T: Trait fn(Cell<&'b u32>)>, - | -------------------------------- required by this bound in `foo` +LL | trait Trait {} + | ----------------- trait `Trait` defined here ... LL | foo::<()>(); - | ^^ the trait `Trait fn(std::cell::Cell<&'b u32>)>` is not implemented for `()` + | ^^^^^^^^^ implementation of `Trait` is not general enough | - = help: the following implementations were found: - <() as Trait)>> + = note: `()` must implement `Trait fn(std::cell::Cell<&'b u32>)>` + = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 4fa404624775b..5e3014317f5bc 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,31 +1,30 @@ -error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied - --> $DIR/hrtb-just-for-static.rs:24:17 +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | fn want_hrtb() - | --------- required by a bound in this -LL | where T : for<'a> Foo<&'a isize> - | ---------------------- required by this bound in `want_hrtb` +LL | / trait Foo { +LL | | fn foo(&self, x: X) { } +LL | | } + | |_- trait `Foo` defined here ... -LL | want_hrtb::() - | ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` +LL | want_hrtb::() + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - > + = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`... + = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1` -error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied - --> $DIR/hrtb-just-for-static.rs:30:17 +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-just-for-static.rs:30:5 | -LL | fn want_hrtb() - | --------- required by a bound in this -LL | where T : for<'a> Foo<&'a isize> - | ---------------------- required by this bound in `want_hrtb` +LL | / trait Foo { +LL | | fn foo(&self, x: X) { } +LL | | } + | |_- trait `Foo` defined here ... -LL | want_hrtb::<&'a u32>() - | ^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32` +LL | want_hrtb::<&'a u32>() + | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - <&'a u32 as Foo<&'a isize>> + = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`... + = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs index 2c85905545807..4a09f4be156e2 100644 --- a/src/test/ui/hrtb/issue-46989.rs +++ b/src/test/ui/hrtb/issue-46989.rs @@ -28,15 +28,13 @@ // // holds because 'a can be instantiated to 'empty. -trait Foo { +trait Foo {} -} - -impl Foo for fn(A) { } +impl Foo for fn(A) {} fn assert_foo() {} fn main() { assert_foo::(); - //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied + //~^ ERROR implementation of `Foo` is not general enough } diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr index 0a7382c4dd818..c85c37ff9239e 100644 --- a/src/test/ui/hrtb/issue-46989.stderr +++ b/src/test/ui/hrtb/issue-46989.stderr @@ -1,15 +1,14 @@ -error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied - --> $DIR/issue-46989.rs:40:18 +error: implementation of `Foo` is not general enough + --> $DIR/issue-46989.rs:38:5 | -LL | fn assert_foo() {} - | --- required by this bound in `assert_foo` +LL | trait Foo {} + | ------------ trait `Foo` defined here ... LL | assert_foo::(); - | ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)` + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = help: the following implementations were found: - + = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)` + = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index 2edc009746455..47cc64ec470a5 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -4,6 +4,8 @@ error[E0599]: no function or associated item named `make_g` found for fn pointer LL | let x = ::make_g(); | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` | + = note: the method `make_g` exists but the following trait bounds were not satisfied: + `for<'r> fn(&'r ()): X` = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it --> $DIR/issue-57362-2.rs:8:1 diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs index 31174fd4cf163..37c6954fd52ee 100644 --- a/src/test/ui/where-clauses/where-for-self-2.rs +++ b/src/test/ui/where-clauses/where-for-self-2.rs @@ -14,9 +14,11 @@ impl Bar for &'static u32 { } fn foo(x: &T) - where for<'a> &'a T: Bar -{} +where + for<'a> &'a T: Bar, +{ +} fn main() { - foo(&X); //~ ERROR trait bound + foo(&X); //~ ERROR implementation of `Bar` is not general enough } diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index 9976243b200dc..30eb78b2da4f7 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,17 +1,16 @@ -error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied - --> $DIR/where-for-self-2.rs:21:5 +error: implementation of `Bar` is not general enough + --> $DIR/where-for-self-2.rs:23:5 | -LL | fn foo(x: &T) - | --- required by a bound in this -LL | where for<'a> &'a T: Bar - | --- required by this bound in `foo` +LL | / trait Bar { +LL | | fn bar(&self); +LL | | } + | |_- trait `Bar` defined here ... -LL | foo(&X); - | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` +LL | foo(&X); + | ^^^ implementation of `Bar` is not general enough | - = help: the following implementations were found: - <&'static u32 as Bar> + = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. From 6873a76f2c34a318a540df65901d07baba1d217b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 May 2020 18:16:28 +0000 Subject: [PATCH 23/30] remove leak-check from project --- .../traits/project.rs | 3 +- .../associated-types-eq-hr.rs | 6 +- .../associated-types-eq-hr.stderr | 78 ++++++++++++++----- .../higher-ranked-projection.bad.stderr | 14 ++-- .../higher-ranked-projection.rs | 2 +- .../closure-arg-type-mismatch.rs | 6 +- .../closure-arg-type-mismatch.stderr | 43 ++++++++-- .../ui/mismatched_types/closure-mismatch.rs | 2 +- .../mismatched_types/closure-mismatch.stderr | 12 ++- src/test/ui/rfc1623.rs | 7 +- src/test/ui/rfc1623.stderr | 35 ++------- .../issue-57611-trait-alias.rs | 2 +- .../issue-57611-trait-alias.stderr | 9 ++- 13 files changed, 132 insertions(+), 87 deletions(-) diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index ae255c22f9dca..bc696214cbc66 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -149,13 +149,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>( debug!("poly_project_and_unify_type(obligation={:?})", obligation); let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { + infcx.commit_if_ok(|_snapshot| { let (placeholder_predicate, _) = infcx.replace_bound_vars_with_placeholders(&obligation.predicate); let placeholder_obligation = obligation.with(placeholder_predicate); let result = project_and_unify_type(selcx, &placeholder_obligation)?; - infcx.leak_check(false, snapshot).map_err(|err| MismatchedProjectionTypes { err })?; Ok(result) }) } diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs index 70e4be5929fb9..fb391913c321e 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.rs +++ b/src/test/ui/associated-types/associated-types-eq-hr.rs @@ -94,12 +94,14 @@ pub fn call_bar() { pub fn call_tuple_one() { tuple_one::(); - //~^ ERROR type mismatch + //~^ ERROR implementation of `TheTrait` is not general enough + //~| ERROR implementation of `TheTrait` is not general enough } pub fn call_tuple_two() { tuple_two::(); - //~^ ERROR type mismatch + //~^ ERROR implementation of `TheTrait` is not general enough + //~| ERROR implementation of `TheTrait` is not general enough } pub fn call_tuple_three() { diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 626cb55588fae..127ab8673556d 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -28,32 +28,72 @@ LL | bar::(); = note: expected reference `&usize` found reference `&isize` -error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` +error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:96:5 | -LL | fn tuple_one() - | --------- required by a bound in this -LL | where -LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>, - | ------------- required by this bound in `tuple_one` +LL | / pub trait TheTrait { +LL | | type A; +LL | | +LL | | fn get(&self, t: T) -> Self::A; +LL | | } + | |_- trait `TheTrait` defined here ... -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` - --> $DIR/associated-types-eq-hr.rs:101:5 +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:96:5 | -LL | fn tuple_two() - | --------- required by a bound in this -LL | where -LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, - | ------------- required by this bound in `tuple_two` +LL | / pub trait TheTrait { +LL | | type A; +LL | | +LL | | fn get(&self, t: T) -> Self::A; +LL | | } + | |_- trait `TheTrait` defined here ... -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:102:5 + | +LL | / pub trait TheTrait { +LL | | type A; +LL | | +LL | | fn get(&self, t: T) -> Self::A; +LL | | } + | |_- trait `TheTrait` defined here +... +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` + +error: implementation of `TheTrait` is not general enough + --> $DIR/associated-types-eq-hr.rs:102:5 + | +LL | / pub trait TheTrait { +LL | | type A; +LL | | +LL | | fn get(&self, t: T) -> Self::A; +LL | | } + | |_- trait `TheTrait` defined here +... +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough + | + = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` error: implementation of `TheTrait` is not general enough - --> $DIR/associated-types-eq-hr.rs:110:5 + --> $DIR/associated-types-eq-hr.rs:112:5 | LL | / pub trait TheTrait { LL | | type A; @@ -68,6 +108,6 @@ LL | tuple_four::(); = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index 3b3e4c3ea117a..811c9a8f5e12b 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr @@ -1,14 +1,12 @@ -error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` +error[E0308]: mismatched types --> $DIR/higher-ranked-projection.rs:25:5 | -LL | fn foo(_t: T) - | --- required by a bound in this -LL | where for<'a> &'a T: Mirror - | ------- required by this bound in `foo` -... LL | foo(()); - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | ^^^ one type is more general than the other + | + = note: expected type `&'a ()` + found type `&()` error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs index 5315e21b0f5a9..1b5476d4c364f 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.rs +++ b/src/test/ui/associated-types/higher-ranked-projection.rs @@ -23,5 +23,5 @@ fn foo(_t: T) #[rustc_error] fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error] foo(()); - //[bad]~^ ERROR type mismatch + //[bad]~^ ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs index fd4463b63e10e..e278049c8cc42 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs @@ -7,5 +7,9 @@ fn main() { fn baz(_: F) {} fn _test<'a>(f: fn(*mut &'a u32)) { - baz(f); //~ ERROR type mismatch + baz(f); + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 503899af33ed7..664fa4bcaf328 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -22,16 +22,43 @@ LL | a.iter().map(|_: (u16, u16)| 45); | | | expected signature of `fn(&(u32, u32)) -> _` -error[E0271]: type mismatch resolving `for<'r> >::Output == ()` +error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 | -LL | fn baz(_: F) {} - | ------------- required by this bound in `baz` -LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); - | ^^^ expected bound lifetime parameter, found concrete lifetime + | ^^^ one type is more general than the other + | + = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` + found type `std::ops::Fn<(*mut &'a u32,)>` + +error[E0308]: mismatched types + --> $DIR/closure-arg-type-mismatch.rs:10:5 + | +LL | baz(f); + | ^^^ one type is more general than the other + | + = note: expected type `std::ops::FnOnce<(*mut &u32,)>` + found type `std::ops::FnOnce<(*mut &'a u32,)>` + +error[E0308]: mismatched types + --> $DIR/closure-arg-type-mismatch.rs:10:5 + | +LL | baz(f); + | ^^^ one type is more general than the other + | + = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` + found type `std::ops::Fn<(*mut &'a u32,)>` + +error[E0308]: mismatched types + --> $DIR/closure-arg-type-mismatch.rs:10:5 + | +LL | baz(f); + | ^^^ one type is more general than the other + | + = note: expected type `std::ops::FnOnce<(*mut &u32,)>` + found type `std::ops::FnOnce<(*mut &'a u32,)>` -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0271, E0631. -For more information about an error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0308, E0631. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs index cb2cb228c62e1..d2b78b4b7dba5 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.rs +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -5,5 +5,5 @@ impl Foo for T {} fn baz(_: T) {} fn main() { - baz(|_| ()); //~ ERROR type mismatch + baz(|_| ()); //~ ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 7fab9490ac93f..d6c17d125cf1e 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,14 +1,12 @@ -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` +error[E0308]: mismatched types --> $DIR/closure-mismatch.rs:8:5 | -LL | fn baz(_: T) {} - | --- required by this bound in `baz` -... LL | baz(|_| ()); - | ^^^ expected bound lifetime parameter, found concrete lifetime + | ^^^ one type is more general than the other | - = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` + = note: expected type `for<'r> std::ops::Fn<(&'r (),)>` + found type `std::ops::Fn<(&(),)>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs index 0564d53b944e6..aa6b1c0012c93 100644 --- a/src/test/ui/rfc1623.rs +++ b/src/test/ui/rfc1623.rs @@ -11,19 +11,18 @@ static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 = struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, bar: &'x Bar<'z>, - f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>, + f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>, } fn id(t: T) -> T { t } -static SOME_STRUCT: &SomeStruct = SomeStruct { - //~^ ERROR mismatched types +static SOME_STRUCT: &SomeStruct = &SomeStruct { foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, - //~^ ERROR type mismatch resolving + //~^ ERROR mismatched types }; // very simple test for a 'static static with default lifetime diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 90dc7cbfa5521..2efc58ac3819c 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -1,35 +1,12 @@ error[E0308]: mismatched types - --> $DIR/rfc1623.rs:21:35 - | -LL | static SOME_STRUCT: &SomeStruct = SomeStruct { - | ___________________________________^ -LL | | -LL | | foo: &Foo { bools: &[false, true] }, -LL | | bar: &Bar { bools: &[true, true] }, -LL | | f: &id, -LL | | -LL | | }; - | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct` - | -help: consider borrowing here - | -LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { -LL | -LL | foo: &Foo { bools: &[false, true] }, -LL | bar: &Bar { bools: &[true, true] }, -LL | f: &id, -LL | - ... - -error[E0271]: type mismatch resolving `for<'a, 'b> ) -> &Foo<'_> {id::<&Foo<'_>>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>` - --> $DIR/rfc1623.rs:25:8 + --> $DIR/rfc1623.rs:24:8 | LL | f: &id, - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | ^^^ one type is more general than the other | - = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>` + found type `std::ops::FnOnce<(&Foo<'_>,)>` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0308. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 84111b1aef8d4..41e019247c942 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -15,7 +15,7 @@ struct X; impl Foo for X { type Bar = impl Baz; - //~^ ERROR type mismatch resolving + //~^ ERROR mismatched types fn bar(&self) -> Self::Bar { |x| x diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index 3cb8abcdcfd17..cd637056c94ad 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -1,11 +1,12 @@ -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X` +error[E0308]: mismatched types --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: the return type of a function must have a statically known size + = note: expected type `std::ops::FnOnce<(&X,)>` + found type `std::ops::FnOnce<(&X,)>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. From 3a68d56de307cae00dd0a9f6908e52889006a1ff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 May 2020 18:19:54 +0000 Subject: [PATCH 24/30] remove `leak_check` from the outlives predicate evaluations --- src/librustc_infer/infer/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 0e569be34aa66..8f8ce03d638c0 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -991,14 +991,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return None; } - Some(self.commit_if_ok(|snapshot| { + Some(self.commit_if_ok(|_snapshot| { let (ty::SubtypePredicate { a_is_expected, a, b }, _) = self.replace_bound_vars_with_placeholders(&predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; - self.leak_check(false, snapshot)?; - Ok(ok.unit()) })) } @@ -1008,14 +1006,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { + self.commit_if_ok(|_snapshot| { let (ty::OutlivesPredicate(r_a, r_b), _) = self.replace_bound_vars_with_placeholders(&predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, snapshot)?; Ok(()) }) } From be0d10f149579d3ed53507ff8c2f6511b56456f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 May 2020 11:05:09 +0000 Subject: [PATCH 25/30] add new tests from MCP and the tracking issue --- .../coherence/coherence-fn-implied-bounds.rs | 14 +++++++ .../coherence-fn-implied-bounds.stderr | 20 ++++++++++ src/test/ui/coherence/coherence-fn-inputs.rs | 27 ++++++++++++++ .../ui/coherence/coherence-fn-inputs.stderr | 13 +++++++ .../coherence-free-vs-bound-region.rs | 21 +++++++++++ .../coherence-free-vs-bound-region.stderr | 20 ++++++++++ .../ui/coherence/coherence-wasm-bindgen.rs | 37 +++++++++++++++++++ .../coherence/coherence-wasm-bindgen.stderr | 32 ++++++++++++++++ src/test/ui/hr-subtype/return-static.rs | 13 +++++++ 9 files changed, 197 insertions(+) create mode 100644 src/test/ui/coherence/coherence-fn-implied-bounds.rs create mode 100644 src/test/ui/coherence/coherence-fn-implied-bounds.stderr create mode 100644 src/test/ui/coherence/coherence-fn-inputs.rs create mode 100644 src/test/ui/coherence/coherence-fn-inputs.stderr create mode 100644 src/test/ui/coherence/coherence-free-vs-bound-region.rs create mode 100644 src/test/ui/coherence/coherence-free-vs-bound-region.stderr create mode 100644 src/test/ui/coherence/coherence-wasm-bindgen.rs create mode 100644 src/test/ui/coherence/coherence-wasm-bindgen.stderr create mode 100644 src/test/ui/hr-subtype/return-static.rs diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.rs b/src/test/ui/coherence/coherence-fn-implied-bounds.rs new file mode 100644 index 0000000000000..ba89a072f3441 --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-implied-bounds.rs @@ -0,0 +1,14 @@ +// Example of coherence impls that we accept + +#![deny(coherence_leak_check)] + +trait Trait {} + +impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} + +impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { + //~^ ERROR conflicting implementations + //~| WARNING this was previously accepted by the compiler +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr new file mode 100644 index 0000000000000..d7853a0b1ebc3 --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr @@ -0,0 +1,20 @@ +error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`: + --> $DIR/coherence-fn-implied-bounds.rs:9:1 + | +LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} + | ------------------------------------------------------------------ first implementation here +LL | +LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` + | +note: the lint level is defined here + --> $DIR/coherence-fn-implied-bounds.rs:3:9 + | +LL | #![deny(coherence_leak_check)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error: aborting due to previous error + diff --git a/src/test/ui/coherence/coherence-fn-inputs.rs b/src/test/ui/coherence/coherence-fn-inputs.rs new file mode 100644 index 0000000000000..8c10899304127 --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-inputs.rs @@ -0,0 +1,27 @@ +// Test that we consider these two types completely equal: +// +// * `for<'a, 'b> fn(&'a u32, &'b u32)` +// * `for<'c> fn(&'c u32, &'c u32)` +// +// For a long time we considered these to be distinct types. But in fact they +// are equivalent, if you work through the implications of subtyping -- this is +// because: +// +// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection) +// * `'a` and `'b` can both be equal to `'c` + +#![deny(coherence_leak_check)] + +trait Trait {} +impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} +impl Trait for for<'c> fn(&'c u32, &'c u32) { + //~^ ERROR conflicting implementations + // + // Note in particular that we do NOT get a future-compatibility warning + // here. This is because the new leak-check proposed in [MCP 295] does not + // "error" when these two types are equated. + // + // [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295 +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-fn-inputs.stderr b/src/test/ui/coherence/coherence-fn-inputs.stderr new file mode 100644 index 0000000000000..a80357526e09d --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-inputs.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`: + --> $DIR/coherence-fn-inputs.rs:17:1 + | +LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} + | ----------------------------------------------- first implementation here +LL | impl Trait for for<'c> fn(&'c u32, &'c u32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)` + | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.rs b/src/test/ui/coherence/coherence-free-vs-bound-region.rs new file mode 100644 index 0000000000000..2f5c49d293d5d --- /dev/null +++ b/src/test/ui/coherence/coherence-free-vs-bound-region.rs @@ -0,0 +1,21 @@ +// Capture a coherence pattern from wasm-bindgen that we discovered as part of +// future-compatibility warning #56105. This pattern currently receives a lint +// warning but we probably want to support it long term. +// +// Key distinction: we are implementing once for `A` (take ownership) and one +// for `&A` (borrow). +// +// c.f. #56105 + +#![deny(coherence_leak_check)] + +trait TheTrait {} + +impl<'a> TheTrait for fn(&'a u8) {} + +impl TheTrait for fn(&u8) { + //~^ ERROR conflicting implementations of trait + //~| WARNING this was previously accepted by the compiler +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.stderr b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr new file mode 100644 index 0000000000000..97aa491272143 --- /dev/null +++ b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr @@ -0,0 +1,20 @@ +error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`: + --> $DIR/coherence-free-vs-bound-region.rs:16:1 + | +LL | impl<'a> TheTrait for fn(&'a u8) {} + | -------------------------------- first implementation here +LL | +LL | impl TheTrait for fn(&u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)` + | +note: the lint level is defined here + --> $DIR/coherence-free-vs-bound-region.rs:10:9 + | +LL | #![deny(coherence_leak_check)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error: aborting due to previous error + diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.rs b/src/test/ui/coherence/coherence-wasm-bindgen.rs new file mode 100644 index 0000000000000..ee09a72449be1 --- /dev/null +++ b/src/test/ui/coherence/coherence-wasm-bindgen.rs @@ -0,0 +1,37 @@ +// Capture a coherence pattern from wasm-bindgen that we discovered as part of +// future-compatibility warning #56105. This pattern currently receives a lint +// warning but we probably want to support it long term. +// +// Key distinction: we are implementing once for `A` (take ownership) and one +// for `&A` (borrow). +// +// c.f. #56105 + +#![deny(coherence_leak_check)] + +trait IntoWasmAbi { + fn some_method(&self) {} +} + +trait FromWasmAbi {} +trait RefFromWasmAbi {} +trait ReturnWasmAbi {} + +impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b) +where + A: FromWasmAbi, + R: ReturnWasmAbi, +{ +} + +// Explicitly writing the bound lifetime. +impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b) +where + A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + //~^^^^^ ERROR conflicting implementation + //~| WARNING this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.stderr b/src/test/ui/coherence/coherence-wasm-bindgen.stderr new file mode 100644 index 0000000000000..c77483bb847f5 --- /dev/null +++ b/src/test/ui/coherence/coherence-wasm-bindgen.stderr @@ -0,0 +1,32 @@ +error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`: + --> $DIR/coherence-wasm-bindgen.rs:28:1 + | +LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b) +LL | | where +LL | | A: FromWasmAbi, +LL | | R: ReturnWasmAbi, +LL | | { +LL | | } + | |_- first implementation here +... +LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b) +LL | | where +LL | | A: RefFromWasmAbi, +LL | | R: ReturnWasmAbi, +... | +LL | | +LL | | } + | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _` + | +note: the lint level is defined here + --> $DIR/coherence-wasm-bindgen.rs:10:9 + | +LL | #![deny(coherence_leak_check)] + | ^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56105 + = note: downstream crates may implement trait `FromWasmAbi` for type `&_` + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error: aborting due to previous error + diff --git a/src/test/ui/hr-subtype/return-static.rs b/src/test/ui/hr-subtype/return-static.rs new file mode 100644 index 0000000000000..6455854f34db8 --- /dev/null +++ b/src/test/ui/hr-subtype/return-static.rs @@ -0,0 +1,13 @@ +// check-pass + +fn make() -> T { + panic!() +} + +fn take(x: T) {} + +fn main() { + let x: for<'a> fn(&'a u32) -> _ = make(); + let y: &'static u32 = x(&22); + take:: fn(&'b u32) -> &'b u32>(x); +} From 93e29823a9eb8de01c33fe48e9f47caf822a2fda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Jun 2020 21:14:34 +0000 Subject: [PATCH 26/30] add new coherence tests and update the documentation --- .../coherence-fn-covariant-bound-vs-static.rs | 26 +++++++++++++++++++ ...erence-fn-covariant-bound-vs-static.stderr | 13 ++++++++++ .../coherence/coherence-fn-implied-bounds.rs | 14 +++++++++- src/test/ui/coherence/coherence-fn-inputs.rs | 2 -- .../ui/coherence/coherence-fn-inputs.stderr | 2 +- 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs create mode 100644 src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs new file mode 100644 index 0000000000000..99f805f7f0f63 --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs @@ -0,0 +1,26 @@ +// Test that impls for these two types are considered ovelapping: +// +// * `for<'r> fn(fn(&'r u32))` +// * `fn(fn(&'a u32)` where `'a` is free +// +// This is because, for `'a = 'static`, the two types overlap. +// Effectively for them to be equal to you get: +// +// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))` +// * true if `exists<'r> { 'r: 'static }` (obviously true) +// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))` +// * true if `forall<'r> { 'static: 'r }` (also true) + +trait Trait {} + +impl Trait for for<'r> fn(fn(&'r ())) {} +impl<'a> Trait for fn(fn(&'a ())) {} +//~^ ERROR conflicting implementations +// +// Note in particular that we do NOT get a future-compatibility warning +// here. This is because the new leak-check proposed in [MCP 295] does not +// "error" when these two types are equated. +// +// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295 + +fn main() {} diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr new file mode 100644 index 0000000000000..1f3a18c7fad9a --- /dev/null +++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`: + --> $DIR/coherence-fn-covariant-bound-vs-static.rs:14:1 + | +LL | impl Trait for for<'r> fn(fn(&'r ())) {} + | ------------------------------------- first implementation here +LL | impl<'a> Trait for fn(fn(&'a ())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))` + | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.rs b/src/test/ui/coherence/coherence-fn-implied-bounds.rs index ba89a072f3441..4539af9a32e38 100644 --- a/src/test/ui/coherence/coherence-fn-implied-bounds.rs +++ b/src/test/ui/coherence/coherence-fn-implied-bounds.rs @@ -1,4 +1,16 @@ -// Example of coherence impls that we accept +// Test that our leak-check is not smart enough to take implied bounds +// into account (yet). Here we have two types that look like they +// should not be equivalent, but because of the rules on implied +// bounds we ought to know that, in fact, `'a = 'b` must always hold, +// and hence they are. +// +// Rustc can't figure this out and hence it accepts the impls but +// gives a future-compatibility warning (because we'd like to make +// this an error someday). +// +// Note that while we would like to make this a hard error, we also +// give the same warning for `coherence-wasm-bindgen.rs`, which ought +// to be accepted. #![deny(coherence_leak_check)] diff --git a/src/test/ui/coherence/coherence-fn-inputs.rs b/src/test/ui/coherence/coherence-fn-inputs.rs index 8c10899304127..3afec5c5459af 100644 --- a/src/test/ui/coherence/coherence-fn-inputs.rs +++ b/src/test/ui/coherence/coherence-fn-inputs.rs @@ -10,8 +10,6 @@ // * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection) // * `'a` and `'b` can both be equal to `'c` -#![deny(coherence_leak_check)] - trait Trait {} impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} impl Trait for for<'c> fn(&'c u32, &'c u32) { diff --git a/src/test/ui/coherence/coherence-fn-inputs.stderr b/src/test/ui/coherence/coherence-fn-inputs.stderr index a80357526e09d..56ab873a39320 100644 --- a/src/test/ui/coherence/coherence-fn-inputs.stderr +++ b/src/test/ui/coherence/coherence-fn-inputs.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`: - --> $DIR/coherence-fn-inputs.rs:17:1 + --> $DIR/coherence-fn-inputs.rs:15:1 | LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} | ----------------------------------------------- first implementation here From c88a76e37b869d6ca343c6ba5d9f0c65deddbca2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 6 Jun 2020 10:31:51 +0000 Subject: [PATCH 27/30] WIP bless test and compare-mode=nll --- ...ect-fn-ret-invariant.krisskross.nll.stderr | 20 +++--- ...project-fn-ret-invariant.oneuse.nll.stderr | 22 +++---- ...ject-fn-ret-invariant.transmute.nll.stderr | 8 +-- .../expect-fn-supply-fn.nll.stderr | 63 ++++++++++--------- ...erence-fn-covariant-bound-vs-static.stderr | 2 +- .../coherence-fn-implied-bounds.stderr | 4 +- ...ubtype.free_inv_x_vs_free_inv_y.nll.stderr | 20 +++--- .../hr-subtype.free_x_vs_free_y.nll.stderr | 10 +-- ...time-bounds-on-fns-where-clause.nll.stderr | 44 ++++++++++--- ...time-bounds-on-fns-where-clause.nll.stderr | 50 ++++++++++++--- .../regions-lifetime-bounds-on-fns.nll.stderr | 44 ++++++++++--- 11 files changed, 186 insertions(+), 101 deletions(-) diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr index 71a533a36f418..4fc336122fa9d 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr @@ -1,26 +1,26 @@ error: lifetime may not live long enough - --> $DIR/project-fn-ret-invariant.rs:55:4 + --> $DIR/project-fn-ret-invariant.rs:56:5 | -LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -- -- lifetime `'b` defined here +LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | (a, b) - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/project-fn-ret-invariant.rs:55:4 + --> $DIR/project-fn-ret-invariant.rs:56:5 | -LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -- -- lifetime `'b` defined here +LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | (a, b) - | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` +LL | (a, b) + | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr index c39030fbed1e1..44850df7b2f42 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr @@ -1,26 +1,26 @@ error: lifetime may not live long enough - --> $DIR/project-fn-ret-invariant.rs:38:12 + --> $DIR/project-fn-ret-invariant.rs:39:13 | -LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -- -- lifetime `'b` defined here +LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -LL | let f = foo; // <-- No consistent type can be inferred for `f` here. -LL | let a = bar(f, x); - | ^^^^^^^^^ argument requires that `'a` must outlive `'b` +LL | let f = foo; // <-- No consistent type can be inferred for `f` here. +LL | let a = bar(f, x); + | ^^^^^^^^^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/project-fn-ret-invariant.rs:39:12 + --> $DIR/project-fn-ret-invariant.rs:40:13 | -LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { - | -- -- lifetime `'b` defined here +LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { + | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here ... -LL | let b = bar(f, y); - | ^^^^^^^^^ argument requires that `'b` must outlive `'a` +LL | let b = bar(f, y); + | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr index f74d4ba73bf4e..db82c9fd43794 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr @@ -1,11 +1,11 @@ error: lifetime may not live long enough - --> $DIR/project-fn-ret-invariant.rs:48:4 + --> $DIR/project-fn-ret-invariant.rs:49:5 | -LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { +LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | -- lifetime `'a` defined here ... -LL | bar(foo, x) - | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` +LL | bar(foo, x) + | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` | = help: consider replacing `'a` with `'static` diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr index 97fdb76dd11c7..64a0b52a1fac5 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr @@ -1,42 +1,43 @@ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:30:5 +error: lifetime may not live long enough + --> $DIR/expect-fn-supply-fn.rs:16:49 | -LL | fn with_closure_expecting_fn_with_free_region(_: F) - | ------------------------------------------ required by a bound in this -LL | where F: for<'a> FnOnce(fn(&'a u32), &i32) - | ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region` +LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { + | -- lifetime `'x` defined here ... -LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `fn(fn(&'a u32), &i32) -> _` +LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); + | ^ + | | + | has type `fn(&'1 u32)` + | requires that `'1` must outlive `'x` -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:37:5 +error: lifetime may not live long enough + --> $DIR/expect-fn-supply-fn.rs:16:49 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` +LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { + | -- lifetime `'x` defined here ... +LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); + | ^ requires that `'x` must outlive `'static` + | + = help: consider replacing `'x` with `'static` + +error: higher-ranked subtype error + --> $DIR/expect-fn-supply-fn.rs:32:49 + | +LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + | ^ + +error: higher-ranked subtype error + --> $DIR/expect-fn-supply-fn.rs:39:50 + | LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^ -error[E0631]: type mismatch in closure arguments - --> $DIR/expect-fn-supply-fn.rs:46:5 +error: higher-ranked subtype error + --> $DIR/expect-fn-supply-fn.rs:48:50 | -LL | fn with_closure_expecting_fn_with_bound_region(_: F) - | ------------------------------------------- required by a bound in this -LL | where F: FnOnce(fn(&u32), &i32) - | ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region` -... LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` + | ^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr index 1f3a18c7fad9a..49271edf8e5e4 100644 --- a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr +++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`: - --> $DIR/coherence-fn-covariant-bound-vs-static.rs:14:1 + --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1 | LL | impl Trait for for<'r> fn(fn(&'r ())) {} | ------------------------------------- first implementation here diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr index d7853a0b1ebc3..a3e7f0bcde376 100644 --- a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr +++ b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr @@ -1,5 +1,5 @@ error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`: - --> $DIR/coherence-fn-implied-bounds.rs:9:1 + --> $DIR/coherence-fn-implied-bounds.rs:21:1 | LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} | ------------------------------------------------------------------ first implementation here @@ -8,7 +8,7 @@ LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` | note: the lint level is defined here - --> $DIR/coherence-fn-implied-bounds.rs:3:9 + --> $DIR/coherence-fn-implied-bounds.rs:15:9 | LL | #![deny(coherence_leak_check)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr index 6b5e7a5a6345a..af5cf41be0a48 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr @@ -1,33 +1,33 @@ error: lifetime may not live long enough - --> $DIR/hr-subtype.rs:33:13 + --> $DIR/hr-subtype.rs:39:13 | -LL | fn subtype<'x,'y:'x,'z:'y>() { - | -- -- lifetime `'y` defined here +LL | fn subtype<'x, 'y: 'x, 'z: 'y>() { + | -- -- lifetime `'y` defined here | | | lifetime `'x` defined here LL | gimme::<$t2>(None::<$t1>); | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation | = help: consider adding the following bound: `'x: 'y` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: lifetime may not live long enough - --> $DIR/hr-subtype.rs:39:13 + --> $DIR/hr-subtype.rs:45:13 | -LL | fn supertype<'x,'y:'x,'z:'y>() { - | -- -- lifetime `'y` defined here +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { + | -- -- lifetime `'y` defined here | | | lifetime `'x` defined here LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` ... LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), -LL | | fn(Inv<'y>)) } - | |__________________________________________________- in this macro invocation +LL | | fn(Inv<'y>)) } + | |______________- in this macro invocation | = help: consider adding the following bound: `'x: 'y` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr index 7c0770924daaa..75d7e0e46b72a 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr @@ -1,16 +1,16 @@ error: lifetime may not live long enough - --> $DIR/hr-subtype.rs:39:13 + --> $DIR/hr-subtype.rs:45:13 | -LL | fn supertype<'x,'y:'x,'z:'y>() { - | -- -- lifetime `'y` defined here +LL | fn supertype<'x, 'y: 'x, 'z: 'y>() { + | -- -- lifetime `'y` defined here | | | lifetime `'x` defined here LL | gimme::<$t1>(None::<$t2>); | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y` ... LL | / check! { free_x_vs_free_y: (fn(&'x u32), -LL | | fn(&'y u32)) } - | |__________________________________________- in this macro invocation +LL | | fn(&'y u32)) } + | |______________- in this macro invocation | = help: consider adding the following bound: `'x: 'y` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr index c3e8789a903b1..695f5506d5e38 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -1,14 +1,40 @@ -error[E0308]: mismatched types - --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43 +error: lifetime may not live long enough + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5 + | +LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Illegal now because there is no `'b:'a` declaration. +LL | *x = *y; + | ^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5 + | +LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | a(x, y); + | ^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: higher-ranked subtype error + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12 | LL | let _: fn(&mut &isize, &mut &isize) = a; - | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12 | - = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr index 2aadd8f4f8c7e..a28f7aa3e08ca 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -1,14 +1,46 @@ -error[E0308]: mismatched types - --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56 +error: lifetime may not live long enough + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5 + | +LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Illegal now because there is no `'b:'a` declaration. +LL | *x = *y; + | ^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5 + | +LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | a(x, y, z); + | ^^^^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: higher-ranked subtype error + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12 | LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; - | ----------------------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12 | - = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)` - found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}` +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12 + | +LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr index 434a3e47b492a..37f7fcf2e331a 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr @@ -1,14 +1,40 @@ -error[E0308]: mismatched types - --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43 +error: lifetime may not live long enough + --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5 + | +LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | // Illegal now because there is no `'b:'a` declaration. +LL | *x = *y; + | ^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: lifetime may not live long enough + --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5 + | +LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | a(x, y); + | ^^^^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: higher-ranked subtype error + --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12 | LL | let _: fn(&mut &isize, &mut &isize) = a; - | ---------------------------- ^ expected concrete lifetime, found bound lifetime parameter - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12 | - = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)` - found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}` +LL | let _: fn(&mut &isize, &mut &isize) = a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0308`. From 6929013b850db7c8ac55de4bcd0df8310ddb788b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Jun 2020 23:12:01 +0000 Subject: [PATCH 28/30] fix subtle bug in NLL type checker The bug was revealed by the behavior of the old-lub-glb-hr-noteq1.rs test. The old-lub-glb-hr-noteq2 test shows the current 'order dependent' behavior of coercions around higher-ranked functions, at least when running with `-Zborrowck=mir`. Also, run compare-mode=nll. --- src/librustc_infer/infer/nll_relate/mod.rs | 8 ++- .../borrow_check/type_check/relate_tys.rs | 2 +- src/librustc_typeck/check/coercion.rs | 20 +++++- .../associated-types-eq-hr.nll.stderr | 33 +++++++++ .../higher-ranked-projection.bad.nll.stderr | 8 +++ .../resume-arg-late-bound.nll.stderr | 8 +++ ...ound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr | 14 ++++ .../hr-subtype.bound_a_vs_free_x.nll.stderr | 14 ++++ ...pe.bound_inv_a_b_vs_bound_inv_a.nll.stderr | 26 +++++++ .../ui/hrtb/hrtb-conflate-regions.nll.stderr | 14 ++++ .../ui/hrtb/hrtb-exists-forall-fn.nll.stderr | 8 +++ ...ists-forall-trait-contravariant.nll.stderr | 8 +++ ...b-exists-forall-trait-invariant.nll.stderr | 8 +++ .../ui/hrtb/hrtb-just-for-static.nll.stderr | 24 +++++++ src/test/ui/hrtb/issue-46989.nll.stderr | 8 +++ src/test/ui/issues/issue-40000.nll.stderr | 8 +++ src/test/ui/lub-glb/old-lub-glb-hr-eq.rs | 27 ++++++++ .../lub-glb/old-lub-glb-hr-noteq1.nll.stderr | 8 +++ src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs | 24 +++++++ ...hr.stderr => old-lub-glb-hr-noteq1.stderr} | 2 +- src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs | 33 +++++++++ .../ui/lub-glb/old-lub-glb-hr-noteq2.stderr | 18 +++++ src/test/ui/lub-glb/old-lub-glb-hr.rs | 57 ---------------- .../ui/lub-glb/old-lub-glb-object.nll.stderr | 14 ++++ .../closure-arg-type-mismatch.nll.stderr | 27 ++++++++ .../closure-mismatch.nll.stderr | 14 ++++ ...fn-subtyping-return-static-fail.nll.stderr | 8 +++ src/test/ui/rfc1623.nll.stderr | 68 +++++++++++++++++++ .../issue-57611-trait-alias.nll.stderr | 14 ++++ .../where-clauses/where-for-self-2.nll.stderr | 8 +++ 30 files changed, 472 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/associated-types/associated-types-eq-hr.nll.stderr create mode 100644 src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr create mode 100644 src/test/ui/generator/resume-arg-late-bound.nll.stderr create mode 100644 src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr create mode 100644 src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr create mode 100644 src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr create mode 100644 src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr create mode 100644 src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr create mode 100644 src/test/ui/hrtb/hrtb-just-for-static.nll.stderr create mode 100644 src/test/ui/hrtb/issue-46989.nll.stderr create mode 100644 src/test/ui/issues/issue-40000.nll.stderr create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-eq.rs create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs rename src/test/ui/lub-glb/{old-lub-glb-hr.stderr => old-lub-glb-hr-noteq1.stderr} (93%) create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs create mode 100644 src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr delete mode 100644 src/test/ui/lub-glb/old-lub-glb-hr.rs create mode 100644 src/test/ui/lub-glb/old-lub-glb-object.nll.stderr create mode 100644 src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr create mode 100644 src/test/ui/mismatched_types/closure-mismatch.nll.stderr create mode 100644 src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr create mode 100644 src/test/ui/rfc1623.nll.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr create mode 100644 src/test/ui/where-clauses/where-for-self-2.nll.stderr diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 8de8925100608..2350c28dfaaff 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -522,7 +522,13 @@ where } if a == b { - return Ok(a); + // Subtle: if a or b has a bound variable that we are lazilly + // substituting, then even if a == b, it could be that the values we + // will substitute for those bound variables are *not* the same, and + // hence returning `Ok(a)` is incorrect. + if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { + return Ok(a); + } } match (&a.kind, &b.kind) { diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index 7ff12820db815..285d9ed64691a 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>( category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible<()> { - debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations); + debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations); TypeRelating::new( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index dec53c369bb18..b6cd8da236260 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -895,7 +895,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let prev_ty = self.resolve_vars_with_obligations(prev_ty); let new_ty = self.resolve_vars_with_obligations(new_ty); - debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); + debug!( + "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", + prev_ty, + new_ty, + exprs.len() + ); // Special-case that coercion alone cannot handle: // Function items or non-capturing closures of differing IDs or InternalSubsts. @@ -1001,6 +1006,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(ok) => { let (adjustments, target) = self.register_infer_ok_obligations(ok); self.apply_adjustments(new, adjustments); + debug!( + "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}", + prev_ty, new_ty, + ); return Ok(target); } Err(e) => first_error = Some(e), @@ -1031,6 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !noop { + debug!( + "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB", + expr, + ); + return self .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .map(|ok| self.register_infer_ok_obligations(ok)); @@ -1048,6 +1062,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } Ok(ok) => { + debug!( + "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}", + prev_ty, new_ty, + ); let (adjustments, target) = self.register_infer_ok_obligations(ok); for expr in exprs { let expr = expr.as_coercion_site(); diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr new file mode 100644 index 0000000000000..25e9f726ba53a --- /dev/null +++ b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr @@ -0,0 +1,33 @@ +error[E0271]: type mismatch resolving `for<'x> >::A == &'x isize` + --> $DIR/associated-types-eq-hr.rs:87:5 + | +LL | fn foo() + | --- required by a bound in this +LL | where +LL | T: for<'x> TheTrait<&'x isize, A = &'x isize>, + | ------------- required by this bound in `foo` +... +LL | foo::(); + | ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize` + | + = note: expected reference `&isize` + found reference `&usize` + +error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` + --> $DIR/associated-types-eq-hr.rs:91:5 + | +LL | fn bar() + | --- required by a bound in this +LL | where +LL | T: for<'x> TheTrait<&'x isize, A = &'x usize>, + | ------------- required by this bound in `bar` +... +LL | bar::(); + | ^^^^^^^^^^^^^^^^ expected `usize`, found `isize` + | + = note: expected reference `&usize` + found reference `&isize` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr new file mode 100644 index 0000000000000..2e03986a9ed8f --- /dev/null +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/higher-ranked-projection.rs:25:5 + | +LL | foo(()); + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr new file mode 100644 index 0000000000000..7d71219192407 --- /dev/null +++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/resume-arg-late-bound.rs:15:5 + | +LL | test(gen); + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr new file mode 100644 index 0000000000000..d5343566633d5 --- /dev/null +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/hr-subtype.rs:45:13 + | +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, +LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } + | |_____________________________________________- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr new file mode 100644 index 0000000000000..f115609396756 --- /dev/null +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/hr-subtype.rs:45:13 + | +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), +LL | | fn(&'x u32)) } + | |______________- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr new file mode 100644 index 0000000000000..4541c462ee056 --- /dev/null +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr @@ -0,0 +1,26 @@ +error: higher-ranked subtype error + --> $DIR/hr-subtype.rs:45:13 + | +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), +LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } + | |__________________________________- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: higher-ranked subtype error + --> $DIR/hr-subtype.rs:45:13 + | +LL | gimme::<$t1>(None::<$t2>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), +LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } + | |__________________________________- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr new file mode 100644 index 0000000000000..f290a93326f37 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-conflate-regions.rs:27:10 + | +LL | fn b() { want_foo2::(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/hrtb-conflate-regions.rs:27:10 + | +LL | fn b() { want_foo2::(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr new file mode 100644 index 0000000000000..11390d9e2d265 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-exists-forall-fn.rs:17:12 + | +LL | let _: for<'b> fn(&'b u32) = foo(); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr new file mode 100644 index 0000000000000..a4c3ffd1f6c08 --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr new file mode 100644 index 0000000000000..e2a399b2faa9d --- /dev/null +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 + | +LL | foo::<()>(); + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr new file mode 100644 index 0000000000000..8901a1b46817d --- /dev/null +++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr @@ -0,0 +1,24 @@ +error: higher-ranked subtype error + --> $DIR/hrtb-just-for-static.rs:24:5 + | +LL | want_hrtb::() + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/hrtb-just-for-static.rs:30:5 + | +LL | fn give_some<'a>() { + | -- lifetime `'a` defined here +LL | want_hrtb::<&'a u32>() + | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + +error: higher-ranked subtype error + --> $DIR/hrtb-just-for-static.rs:30:5 + | +LL | want_hrtb::<&'a u32>() + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr new file mode 100644 index 0000000000000..6c127b92d97d1 --- /dev/null +++ b/src/test/ui/hrtb/issue-46989.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/issue-46989.rs:38:5 + | +LL | assert_foo::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr new file mode 100644 index 0000000000000..f673fbae8b79c --- /dev/null +++ b/src/test/ui/issues/issue-40000.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/issue-40000.rs:6:9 + | +LL | foo(bar); + | ^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs new file mode 100644 index 0000000000000..fbf4aee02045d --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs @@ -0,0 +1,27 @@ +// Test that we give a note when the old LUB/GLB algorithm would have +// succeeded but the new code (which requires equality) gives an +// error. However, now that we handle subtyping correctly, we no +// longer get an error, because we recognize these two types as +// equivalent! +// +// check-pass + +fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) { + // The two types above are actually equivalent. With the older + // leak check, though, we didn't consider them as equivalent, and + // hence we gave errors. But now we've fixed that. + let z = match 22 { + 0 => x, + _ => y, + }; +} + +fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) { + let z = match 22 { + // No error with an explicit cast: + 0 => x as for<'a> fn(&'a u8, &'a u8), + _ => y, + }; +} + +fn main() {} diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr new file mode 100644 index 0000000000000..b95e247d2a8cf --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/old-lub-glb-hr-noteq1.rs:11:14 + | +LL | _ => y, + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs new file mode 100644 index 0000000000000..918542d471b58 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs @@ -0,0 +1,24 @@ +// Test taking the LUB of two function types that are not equatable but where one is more +// general than the other. Test the case where the more general type (`x`) is the first +// match arm specifically. + +fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) { + // The two types above are not equivalent. With the older LUB/GLB + // algorithm, this may have worked (I don't remember), but now it + // doesn't because we require equality. + let z = match 22 { + 0 => x, + _ => y, //~ ERROR `match` arms have incompatible types + }; +} + +fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) { + // But we can *upcast* explicitly the type of `x` and figure + // things out: + let z = match 22 { + 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, + _ => y, + }; +} + +fn main() {} diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr similarity index 93% rename from src/test/ui/lub-glb/old-lub-glb-hr.stderr rename to src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr index f9ad4e5814eeb..305e952d6046b 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr @@ -1,5 +1,5 @@ error[E0308]: `match` arms have incompatible types - --> $DIR/old-lub-glb-hr.rs:40:14 + --> $DIR/old-lub-glb-hr-noteq1.rs:11:14 | LL | let z = match 22 { | _____________- diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs new file mode 100644 index 0000000000000..0e069bc6f84e9 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs @@ -0,0 +1,33 @@ +// Test taking the LUB of two function types that are not equatable but where +// one is more general than the other. Test the case where the more general type +// (`x`) is the second match arm specifically. +// +// Skip for compare-mode because the pure NLL checker accepts this test. (Note +// that it still errors in old-lub-glb-hr-noteq1.rs). What happens is that, due +// to the ordering of the match arms, we pick the correct "more general" fn +// type, and we ignore the errors from the non-NLL type checker that requires +// equality. The NLL type checker only requires a subtyping relationship, and +// that holds. +// +// ignore-compare-mode-nll + +fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) { + // The two types above are not equivalent. With the older LUB/GLB + // algorithm, this may have worked (I don't remember), but now it + // doesn't because we require equality. + let z = match 22 { + 0 => y, + _ => x, //~ ERROR `match` arms have incompatible types + }; +} + +fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) { + // But we can *upcast* explicitly the type of `x` and figure + // things out: + let z = match 22 { + 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, + _ => y, + }; +} + +fn main() {} diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr new file mode 100644 index 0000000000000..252e13aada054 --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr @@ -0,0 +1,18 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/old-lub-glb-hr-noteq2.rs:20:14 + | +LL | let z = match 22 { + | _____________- +LL | | 0 => y, + | | - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8` +LL | | _ => x, + | | ^ one type is more general than the other +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` + found fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs deleted file mode 100644 index 5e24a99bcc331..0000000000000 --- a/src/test/ui/lub-glb/old-lub-glb-hr.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Test that we give a note when the old LUB/GLB algorithm would have -// succeeded but the new code (which requires equality) gives an -// error. However, now that we handle subtyping correctly, we no -// longer get an error, because we recognize these two types as -// equivalent! - -fn foo( - x: fn(&u8, &u8), - y: for<'a> fn(&'a u8, &'a u8), -) { - // The two types above are actually equivalent. With the older - // leak check, though, we didn't consider them as equivalent, and - // hence we gave errors. But now we've fixed that. - let z = match 22 { - 0 => x, - _ => y, - }; -} - -fn foo_cast( - x: fn(&u8, &u8), - y: for<'a> fn(&'a u8, &'a u8), -) { - let z = match 22 { - // No error with an explicit cast: - 0 => x as for<'a> fn(&'a u8, &'a u8), - _ => y, - }; -} - -fn bar( - x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, - y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, -) { - // The two types above are not equivalent. With the older LUB/GLB - // algorithm, this may have worked (I don't remember), but now it - // doesn't because we require equality. - let z = match 22 { - 0 => x, - _ => y, //~ ERROR `match` arms have incompatible types - }; -} - -fn bar_cast( - x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8, - y: for<'a> fn(&'a u8, &'a u8) -> &'a u8, -) { - // But we can *upcast* explicitly the type of `x` and figure - // things out: - let z = match 22 { - 0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8, - _ => y, - }; -} - -fn main() { -} diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr new file mode 100644 index 0000000000000..51bf96f32335b --- /dev/null +++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/old-lub-glb-object.rs:10:14 + | +LL | _ => y, + | ^ + +error: higher-ranked subtype error + --> $DIR/old-lub-glb-object.rs:10:14 + | +LL | _ => y, + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr new file mode 100644 index 0000000000000..6ed91b20ab8a6 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr @@ -0,0 +1,27 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:3:14 + | +LL | a.iter().map(|_: (u32, u32)| 45); + | ^^^ ------------------ found signature of `fn((u32, u32)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:4:14 + | +LL | a.iter().map(|_: &(u16, u16)| 45); + | ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error[E0631]: type mismatch in closure arguments + --> $DIR/closure-arg-type-mismatch.rs:5:14 + | +LL | a.iter().map(|_: (u16, u16)| 45); + | ^^^ ------------------ found signature of `fn((u16, u16)) -> _` + | | + | expected signature of `fn(&(u32, u32)) -> _` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr new file mode 100644 index 0000000000000..745a61b866ed2 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/closure-mismatch.rs:8:5 + | +LL | baz(|_| ()); + | ^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/closure-mismatch.rs:8:5 + | +LL | baz(|_| ()); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr new file mode 100644 index 0000000000000..d762f55f9d5f1 --- /dev/null +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5 + | +LL | want_G(baz); + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr new file mode 100644 index 0000000000000..848d4fef1abfc --- /dev/null +++ b/src/test/ui/rfc1623.nll.stderr @@ -0,0 +1,68 @@ +error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely + --> $DIR/rfc1623.rs:21:1 + | +LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct { +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | }; + | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely + | + = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = note: required because it appears within the type `SomeStruct` + = note: required because it appears within the type `&SomeStruct` + = note: shared static variables must have a type that implements `Sync` + +error: higher-ranked subtype error + --> $DIR/rfc1623.rs:21:35 + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | }; + | |_^ + +error: higher-ranked subtype error + --> $DIR/rfc1623.rs:21:35 + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | }; + | |_^ + +error: higher-ranked subtype error + --> $DIR/rfc1623.rs:21:35 + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | }; + | |_^ + +error: higher-ranked subtype error + --> $DIR/rfc1623.rs:21:35 + | +LL | static SOME_STRUCT: &SomeStruct = &SomeStruct { + | ___________________________________^ +LL | | foo: &Foo { bools: &[false, true] }, +LL | | bar: &Bar { bools: &[true, true] }, +LL | | f: &id, +LL | | +LL | | }; + | |_^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr new file mode 100644 index 0000000000000..8c9cb742fac91 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/issue-57611-trait-alias.rs:21:9 + | +LL | |x| x + | ^^^^^ + +error: higher-ranked subtype error + --> $DIR/issue-57611-trait-alias.rs:21:9 + | +LL | |x| x + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr new file mode 100644 index 0000000000000..d0c476dc6ec05 --- /dev/null +++ b/src/test/ui/where-clauses/where-for-self-2.nll.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/where-for-self-2.rs:23:5 + | +LL | foo(&X); + | ^^^^^^^ + +error: aborting due to previous error + From d57689f9cde9a7066ffc8ca1125ea7e0d23df2c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Jun 2020 23:22:10 +0000 Subject: [PATCH 29/30] cite issue 73154 --- src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs index 0e069bc6f84e9..4bdd05b4f92fa 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs @@ -2,12 +2,12 @@ // one is more general than the other. Test the case where the more general type // (`x`) is the second match arm specifically. // -// Skip for compare-mode because the pure NLL checker accepts this test. (Note -// that it still errors in old-lub-glb-hr-noteq1.rs). What happens is that, due -// to the ordering of the match arms, we pick the correct "more general" fn -// type, and we ignore the errors from the non-NLL type checker that requires -// equality. The NLL type checker only requires a subtyping relationship, and -// that holds. +// FIXME(#73154) Skip for compare-mode because the pure NLL checker accepts this +// test. (Note that it still errors in old-lub-glb-hr-noteq1.rs). What happens +// is that, due to the ordering of the match arms, we pick the correct "more +// general" fn type, and we ignore the errors from the non-NLL type checker that +// requires equality. The NLL type checker only requires a subtyping +// relationship, and that holds. // // ignore-compare-mode-nll From 3eb8eb942951d66fe1f0cc1be3a47cd9f147fc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 22 Jun 2020 16:05:31 -0700 Subject: [PATCH 30/30] review comments --- .../error_reporting/nice_region_error/named_anon_conflict.rs | 5 +++-- .../error_reporting/nice_region_error/static_impl_trait.rs | 2 +- src/librustc_middle/ty/context.rs | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 7c8ba834dcdcb..3012928a09854 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -92,9 +92,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .next() .is_some() { + // If the failure is due to a `'static` requirement coming from a `dyn` or + // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case + // better in `static_impl_trait`. debug!("try_report_named_anon_conflict: impl Trait + 'static"); - // This is an `impl Trait` or `dyn Trait` return that evaluates de need of - // `'static`. We handle this case better in `static_impl_trait`. return None; } } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 20b275ea34af0..46dad81a099bb 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -26,7 +26,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); - let fn_returns = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id); + let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id); if fn_returns.is_empty() { return None; } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 73374bb1e8443..e8ea7dba21720 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1406,7 +1406,8 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> { + /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. + pub fn return_type_impl_or_dyn_traits(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); let hir_output = match self.hir().get(hir_id) { Node::Item(hir::Item {