From 3a4921cde162af1ffbb2fbff4b395408eab1deab Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Sep 2019 14:45:19 +0200 Subject: [PATCH 1/3] The crux of the bug fix. Update: review feedback Update: placate tidy --- src/librustc_resolve/late.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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() From a18d424c48e5b2e23cebf5ab5969a3254ab90a9e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Sep 2019 15:21:02 +0200 Subject: [PATCH 2/3] Allocate a new diagnostic for defaulted type parameters cannot use `Self` (Without this commit, you still get an error (a very similar one, at that), but it complains about use of forward declaration, which is confusing since people do not necessarily think of `Self` as being declared at all.) Update: incorporate review feedback. --- src/librustc_resolve/diagnostics.rs | 11 +++++++++++ src/librustc_resolve/error_codes.rs | 23 +++++++++++++++++++---- src/librustc_resolve/lib.rs | 12 ++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) 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/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; From e443e1bdf9f474f822008f88862fed630b50381f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Sep 2019 15:21:16 +0200 Subject: [PATCH 3/3] Regression tests. Update: incorporate review feedback. --- ...-type-param-can-reference-self-in-trait.rs | 20 +++++++++ ...e-param-can-reference-self-in-trait.stderr | 12 +++++ ...efault-type-param-cannot-reference-self.rs | 45 +++++++++++++++++++ ...lt-type-param-cannot-reference-self.stderr | 39 ++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs create mode 100644 src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr create mode 100644 src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.rs create mode 100644 src/test/ui/generics/issue-61631-default-type-param-cannot-reference-self.stderr 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`.