diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index c479912b4ef81..7f819486f5bd3 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -354,6 +354,17 @@ impl<'a> Resolver<'a> { span, "defaulted type parameters cannot be forward declared".to_string()); err } + ResolutionError::SelfInTyParamDefault => { + let mut err = struct_span_err!( + self.session, + span, + E0735, + "type parameters cannot use `Self` in their defaults" + ); + err.span_label( + span, "`Self` in type parameter default".to_string()); + err + } ResolutionError::ConstParamDependentOnTypeParam => { let mut err = struct_span_err!( self.session, diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 9a39fcf422393..47346774180fe 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -8,9 +8,9 @@ Type parameter defaults can only use parameters that occur before them. Erroneous code example: ```compile_fail,E0128 -struct Foo { +struct Foo { field1: T, - filed2: U, + field2: U, } // error: type parameters with a default cannot use forward declared // identifiers @@ -20,9 +20,9 @@ Since type parameters are evaluated in-order, you may be able to fix this issue by doing: ``` -struct Foo { +struct Foo { field1: T, - filed2: U, + field2: U, } ``` @@ -1705,6 +1705,21 @@ fn const_id() -> T { // error: const parameter } ``` "##, + +E0735: r##" +Type parameter defaults cannot use `Self` on structs, enums, or unions. + +Erroneous code example: + +```compile_fail,E0735 +struct Foo> { + field1: Option, + field2: Option, +} +// error: type parameters cannot use `Self` in their defaults. +``` +"##, + ; // E0153, unused error code // E0157, unused error code diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 33a85c6c77026..93c96b9f75ba2 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -468,6 +468,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { } })); + // rust-lang/rust#61631: The type `Self` is essentially + // another type parameter. For ADTs, we consider it + // well-defined only after all of the ADT type parameters have + // been provided. Therefore, we do not allow use of `Self` + // anywhere in ADT type parameter defaults. + // + // (We however cannot ban `Self` for defaults on *all* generic + // lists; e.g. trait generics can usefully refer to `Self`, + // such as in the case of `trait Add`.) + if self.current_self_item.is_some() { // (`Some` if + only if we are in ADT's generics.) + default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); + } + // We also ban access to type parameters for use as the types of const parameters. let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); const_ty_param_ban_rib.bindings.extend(generics.params.iter() diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bf86a37433840..e7292b52ab3e8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -214,6 +214,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// Error E0735: type parameters with a default cannot use `Self` + SelfInTyParamDefault, /// Error E0671: const parameter cannot depend on type parameter. ConstParamDependentOnTypeParam, } @@ -1536,7 +1538,7 @@ impl<'a> Resolver<'a> { if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res( - self.validate_res_from_ribs(i, res, record_used, path_span, ribs), + self.validate_res_from_ribs(i, rib_ident, res, record_used, path_span, ribs), )); } @@ -2122,6 +2124,7 @@ impl<'a> Resolver<'a> { fn validate_res_from_ribs( &mut self, rib_index: usize, + rib_ident: Ident, res: Res, record_used: bool, span: Span, @@ -2133,7 +2136,12 @@ impl<'a> Resolver<'a> { // An invalid forward use of a type parameter from a previous default. if let ForwardTyParamBanRibKind = all_ribs[rib_index].kind { if record_used { - self.report_error(span, ResolutionError::ForwardDeclaredTyParam); + let res_error = if rib_ident.name == kw::SelfUpper { + ResolutionError::SelfInTyParamDefault + } else { + ResolutionError::ForwardDeclaredTyParam + }; + self.report_error(span, res_error); } assert_eq!(res, Res::Err); return Res::Err; diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs new file mode 100644 index 0000000000000..cc93794e8fcdc --- /dev/null +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs @@ -0,0 +1,20 @@ +#![crate_type="lib"] + +// rust-lang/rust#61631: The use of `Self` in the defaults of generic +// types in a *trait* definition are allowed. +// +// It *must* be accepted; we have used this pattern extensively since +// Rust 1.0 (see e.g. `trait Add`). +trait Tnobound

{} + +impl Tnobound for () { } + +// This variant is accepted at the definition site; but it will be +// rejected at every possible usage site (such as the one immediately +// below). Maybe one day we will attempt to catch it at the definition +// site, but today this is accepted due to compiler implementation +// limitations. +trait Tsized {} + +impl Tsized for () {} +//~^ ERROR the size for values of type `[()]` cannot be known at compilation time [E0277] diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr new file mode 100644 index 0000000000000..ea0664c48d4d8 --- /dev/null +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `[()]` cannot be known at compilation time + --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:19:6 + | +LL | impl Tsized for () {} + | ^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[()]` + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.rs b/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.rs new file mode 100644 index 0000000000000..b560cc2ce7060 --- /dev/null +++ b/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.rs @@ -0,0 +1,45 @@ +#![crate_type="lib"] + +// rust-lang/rust#61631: Uses of `Self` in the defaults of generic +// types for ADT's are not allowed. We justify this because the `Self` +// type could be considered the "final" type parameter, that is only +// well-defined after all of the other type parameters on the ADT have +// been instantiated. +// +// These were previously were ICE'ing at the usage point anyway (see +// `demo_usages` below), so there should not be any backwards +// compatibility concern. + +struct Snobound<'a, P = Self> { x: Option<&'a P> } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +enum Enobound<'a, P = Self> { A, B(Option<&'a P>) } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +union Unobound<'a, P = Self> { x: i32, y: Option<&'a P> } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +// Disallowing `Self` in defaults sidesteps need to check the bounds +// on the defaults in cases like these. + +struct Ssized<'a, P: Sized = [Self]> { x: Option<&'a P> } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +enum Esized<'a, P: Sized = [Self]> { A, B(Option<&'a P>) } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +union Usized<'a, P: Sized = [Self]> { x: i32, y: Option<&'a P> } +//~^ ERROR type parameters cannot use `Self` in their defaults [E0735] + +fn demo_usages() { + // An ICE means you only get the error from the first line of the + // demo; comment each out to observe the other ICEs when trying + // this out on older versions of Rust. + + let _ice: Snobound; + let _ice: Enobound; + let _ice: Unobound; + let _ice: Ssized; + let _ice: Esized; + let _ice: Usized; +} diff --git a/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.stderr b/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.stderr new file mode 100644 index 0000000000000..689ffbd0febc2 --- /dev/null +++ b/src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.stderr @@ -0,0 +1,39 @@ +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:13:25 + | +LL | struct Snobound<'a, P = Self> { x: Option<&'a P> } + | ^^^^ `Self` in type parameter default + +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:16:23 + | +LL | enum Enobound<'a, P = Self> { A, B(Option<&'a P>) } + | ^^^^ `Self` in type parameter default + +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:19:24 + | +LL | union Unobound<'a, P = Self> { x: i32, y: Option<&'a P> } + | ^^^^ `Self` in type parameter default + +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:25:31 + | +LL | struct Ssized<'a, P: Sized = [Self]> { x: Option<&'a P> } + | ^^^^ `Self` in type parameter default + +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:28:29 + | +LL | enum Esized<'a, P: Sized = [Self]> { A, B(Option<&'a P>) } + | ^^^^ `Self` in type parameter default + +error[E0735]: type parameters cannot use `Self` in their defaults + --> $DIR/issue-61631-default-type-param-cannot-reference-self.rs:31:30 + | +LL | union Usized<'a, P: Sized = [Self]> { x: i32, y: Option<&'a P> } + | ^^^^ `Self` in type parameter default + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0735`.