diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index c6e42336ef8ca..9d8812b7eeaac 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -12,6 +12,8 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; +use crate::session_diagnostics::NonGenericOpaqueTypeParam; + use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -389,17 +391,13 @@ fn check_opaque_type_parameter_valid( } else { // Prevent `fn foo() -> Foo` from being defining. let opaque_param = opaque_generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); + let kind = opaque_param.kind.descr(); + tcx.sess.emit_err(NonGenericOpaqueTypeParam { + ty: arg, + kind, + span, + param_span: tcx.def_span(opaque_param.def_id), + }); return false; } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 577332c0744b8..23acf159240fa 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use rustc_errors::{IntoDiagnosticArg, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; use crate::diagnostics::RegionName; @@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> { #[label] pub borrow_span: Span, } + +#[derive(Diagnostic)] +#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")] +pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { + pub ty: GenericArg<'tcx>, + pub kind: &'a str, + #[primary_span] + pub span: Span, + #[label] + pub param_span: Span, +} diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 24258974bb97c..5c77448f908ed 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -508,6 +508,7 @@ E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), +E0792: include_str!("./error_codes/E0792.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md new file mode 100644 index 0000000000000..bad2b5abfe4d7 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0792.md @@ -0,0 +1,60 @@ +A type alias impl trait can only have its hidden type assigned +when used fully generically (and within their defining scope). +This means + +```compile_fail,E0792 +#![feature(type_alias_impl_trait)] + +type Foo = impl std::fmt::Debug; + +fn foo() -> Foo { + 5u32 +} +``` + +is not accepted. If it were accepted, one could create unsound situations like + +```compile_fail,E0792 +#![feature(type_alias_impl_trait)] + +type Foo = impl Default; + +fn foo() -> Foo { + 5u32 +} + +fn main() { + let x = Foo::<&'static mut String>::default(); +} +``` + + +Instead you need to make the function generic: + +``` +#![feature(type_alias_impl_trait)] + +type Foo = impl std::fmt::Debug; + +fn foo() -> Foo { + 5u32 +} +``` + +This means that no matter the generic parameter to `foo`, +the hidden type will always be `u32`. +If you want to link the generic parameter to the hidden type, +you can do that, too: + + +``` +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; + +type Foo = impl Debug; + +fn foo() -> Foo { + Vec::::new() +} +``` diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index 2cd4733220e82..9e4332c428386 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -120,3 +120,7 @@ borrowck_cannot_move_when_borrowed = [value] value *[other] {$value_place} } occurs here + +borrowck_opaque_type_non_generic_param = + expected generic {$kind} parameter, found `{$ty}` + .label = this generic parameter must be used with a generic {$kind} parameter diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c22df7395f10..771b63f59c124 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -17,7 +17,7 @@ use rustc_type_ir::sty::TyKind::*; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() + self.to_string().into_diagnostic_arg() } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 8f764011d0ac3..75a8dda315765 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -7,6 +7,7 @@ use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; @@ -36,6 +37,12 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.rs b/tests/ui/type-alias-impl-trait/bound_reduction2.rs index 4d2890b5de583..0bcc9e002ca04 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.rs @@ -14,5 +14,5 @@ impl Trait for () {} fn foo_desugared(_: T) -> Foo { () - //~^ ERROR non-defining opaque type use + //~^ ERROR expected generic type parameter, found `::Assoc` } diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr index c405b1f6af205..3c259bd9e97cc 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `::Assoc` --> $DIR/bound_reduction2.rs:16:5 | +LL | type Foo = impl Trait; + | - this generic parameter must be used with a generic type parameter +... LL | () | ^^ - | -note: used non-generic type `::Assoc` for generic parameter - --> $DIR/bound_reduction2.rs:9:10 - | -LL | type Foo = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index f39741a6a625c..f5045d382aac4 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -10,12 +10,11 @@ type OneLifetime<'a> = impl Debug; type OneConst = impl Debug; - // Not defining uses, because they doesn't define *all* possible generics. fn concrete_ty() -> OneTy { 5u32 - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic type parameter, found `u32` } fn concrete_lifetime() -> OneLifetime<'static> { @@ -25,5 +24,5 @@ fn concrete_lifetime() -> OneLifetime<'static> { fn concrete_const() -> OneConst<{ 123 }> { 7u32 - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic constant parameter, found `123` } diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr index e7565525ad338..564648630b161 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -1,17 +1,14 @@ -error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:17:5 +error[E0792]: expected generic type parameter, found `u32` + --> $DIR/generic_nondefining_use.rs:16:5 | +LL | type OneTy = impl Debug; + | - this generic parameter must be used with a generic type parameter +... LL | 5u32 | ^^^^ - | -note: used non-generic type `u32` for generic parameter - --> $DIR/generic_nondefining_use.rs:7:12 - | -LL | type OneTy = impl Debug; - | ^ error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:22:5 + --> $DIR/generic_nondefining_use.rs:21:5 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -19,17 +16,15 @@ LL | type OneLifetime<'a> = impl Debug; LL | 6u32 | ^^^^ -error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:27:5 +error[E0792]: expected generic constant parameter, found `123` + --> $DIR/generic_nondefining_use.rs:26:5 | +LL | type OneConst = impl Debug; + | -------------- this generic parameter must be used with a generic constant parameter +... LL | 7u32 | ^^^^ - | -note: used non-generic constant `123` for generic parameter - --> $DIR/generic_nondefining_use.rs:11:15 - | -LL | type OneConst = impl Debug; - | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index cb90776472b5d..d3e169a70d3f7 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -4,7 +4,7 @@ fn main() { let y = 42; let x = wrong_generic(&y); let z: i32 = x; - //~^ ERROR non-defining opaque type use + //~^ ERROR expected generic type parameter, found `&'static i32 } type WrongGeneric = impl 'static; diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index ba583241a696b..19115fd28662b 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -4,17 +4,14 @@ error: at least one trait must be specified LL | type WrongGeneric = impl 'static; | ^^^^^^^^^^^^ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `&'static i32` --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | LL | let z: i32 = x; | ^ - | -note: used non-generic type `&'static i32` for generic parameter - --> $DIR/generic_type_does_not_live_long_enough.rs:10:19 - | +... LL | type WrongGeneric = impl 'static; - | ^ + | - this generic parameter must be used with a generic type parameter error[E0310]: the parameter type `T` may not live long enough --> $DIR/generic_type_does_not_live_long_enough.rs:14:5 @@ -29,4 +26,5 @@ LL | fn wrong_generic(t: T) -> WrongGeneric { error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0310`. +Some errors have detailed explanations: E0310, E0792. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/type-alias-impl-trait/issue-60564.rs b/tests/ui/type-alias-impl-trait/issue-60564.rs index 4fc7679311a2e..c2f4c37080746 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.rs +++ b/tests/ui/type-alias-impl-trait/issue-60564.rs @@ -18,7 +18,7 @@ where type BitsIter = IterBitsIter; fn iter_bits(self, n: u8) -> Self::BitsIter { (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic type parameter, found `u8` } } diff --git a/tests/ui/type-alias-impl-trait/issue-60564.stderr b/tests/ui/type-alias-impl-trait/issue-60564.stderr index bbc93657be32f..f8fdb004d0989 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.stderr +++ b/tests/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `u8` --> $DIR/issue-60564.rs:20:9 | +LL | type IterBitsIter = impl std::iter::Iterator; + | - this generic parameter must be used with a generic type parameter +... LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: used non-generic type `u8` for generic parameter - --> $DIR/issue-60564.rs:8:25 - | -LL | type IterBitsIter = impl std::iter::Iterator; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs index 5223fb1c702d6..5e0a82a72868a 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs @@ -7,7 +7,7 @@ trait Trait {} type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr index 7fb9a0c410e83..271743a4010c8 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use-2.rs:9:29 | +LL | type Alias<'a, U> = impl Trait; + | - this generic parameter must be used with a generic type parameter +LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-68368-non-defining-use-2.rs:7:16 - | -LL | type Alias<'a, U> = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index b50462bf237bb..3b32260c96fe1 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -7,7 +7,7 @@ trait Trait {} type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index 8059621b61a09..4d9a8d6eef915 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,14 +1,12 @@ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use.rs:9:29 | +LL | type Alias<'a, U> = impl Trait; + | - this generic parameter must be used with a generic type parameter +LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-68368-non-defining-use.rs:7:16 - | -LL | type Alias<'a, U> = impl Trait; - | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index 428454bc04844..7657fe2fb1aee 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -18,6 +18,6 @@ type Return = impl WithAssoc; //~^ ERROR use of undeclared lifetime name `'a` fn my_fun() -> Return<()> {} -//~^ ERROR non-defining opaque type use in defining scope +//~^ ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index 7b50c8af26e5f..d1250786d938c 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -14,18 +14,16 @@ help: consider introducing lifetime `'a` here LL | type Return<'a, A> = impl WithAssoc; | +++ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 | +LL | type Return = impl WithAssoc; + | - this generic parameter must be used with a generic type parameter +... LL | fn my_fun() -> Return<()> {} | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 - | -LL | type Return = impl WithAssoc; - | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0792. +For more information about an error, try `rustc --explain E0261`.