From a5ba21dac9da633e7ad456027a1d076f43075b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 5 Mar 2020 11:10:58 -0800 Subject: [PATCH] Perform WF-check on `type`s with no type parameters Start performing a WF-check on `type`s to verify that they will be able to be constructed. Do *not* perform a `Sized` check, as `type T = dyn Trait;` should be allowed. Do *not* WF-check `type`s with type parameters because we currently lint *against* `type T = K;` because we do not propagate `X: Trait`, which means that we currently allow `type T = ::Foo;`, which would be rejected if we WF-checked it because it would need to be written as `type T = ::Foo;` to be correct. Instead, we simply don't check it at definition and only do so at use like we do currently. In the future, the alternatives would be to either automatically backpropagate the `X: Trait` obligation when WF-checking the `type` or (my preferred solution) properly propagate the explicit `X: Trait` obligation to the uses, which would likely be a breaking change. Fixes #60980 by using a more appropriate span for the error. --- compiler/rustc_typeck/src/check/wfcheck.rs | 17 ++++++ .../cfg-generic-params.rs | 6 ++- .../cfg-generic-params.stderr | 53 ++++++++++++++++--- .../ui/consts/const-eval/pub_const_err.rs | 3 +- .../ui/consts/const-eval/pub_const_err_bin.rs | 3 +- src/test/ui/consts/const_let_assign3.rs | 7 --- src/test/ui/consts/const_let_assign3.stderr | 11 +--- src/test/ui/consts/const_let_assign4.rs | 31 +++++++++++ src/test/ui/consts/const_let_assign4.stderr | 12 +++++ .../feature-gate-trivial_bounds.rs | 2 +- .../feature-gate-trivial_bounds.stderr | 11 +++- src/test/ui/hygiene/assoc_ty_bindings.rs | 8 +-- src/test/ui/resolve/issue-3907-2.rs | 5 +- src/test/ui/resolve/issue-3907-2.stderr | 14 ++++- .../ui/structs/struct-path-alias-bounds.rs | 3 +- .../structs/struct-path-alias-bounds.stderr | 8 +-- 16 files changed, 150 insertions(+), 44 deletions(-) create mode 100644 src/test/ui/consts/const_let_assign4.rs create mode 100644 src/test/ui/consts/const_let_assign4.stderr diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 00c6550835b43..bd1499875d027 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -163,6 +163,23 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } + hir::ItemKind::TyAlias(ref ty, hir::Generics { params: [], .. }) => { + // We explicitely only check cases with *no* type parameters to avoid regressions on + // existing incorrectly accepted code like `type T = ::Foo;`. + + // We don't use `check_item_type` to *not* emit `!Sized` errors. + let ty_span = ty.span; + for_id(tcx, item.hir_id(), ty_span).with_fcx(|fcx, tcx| { + let ty = tcx.type_of(def_id); + let item_ty = fcx.normalize_associated_types_in(ty_span, ty); + fcx.register_wf_obligation( + item_ty.into(), + ty_span, + ObligationCauseCode::MiscObligation, + ); + vec![] + }); + } hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { check_type_defn(tcx, item, false, |fcx| vec![fcx.non_enum_variant(struct_def)]); diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.rs b/src/test/ui/conditional-compilation/cfg-generic-params.rs index 53aa3556362f9..96554cd600db5 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.rs +++ b/src/test/ui/conditional-compilation/cfg-generic-params.rs @@ -7,9 +7,11 @@ type FnGood = for<#[cfg(yes)] 'a, #[cfg(no)] T> fn(); // OK type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); //~^ ERROR only lifetime parameters can be used in this context -type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(no)] T> Copy; // OK +type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(no)] T> Copy; +//~^ ERROR the trait `Copy` cannot be made into an object type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; //~^ ERROR only lifetime parameters can be used in this context +//~| ERROR the trait `Copy` cannot be made into an object struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(no)] T> u8: Copy; // OK struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; @@ -27,8 +29,10 @@ type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); //~^ ERROR cannot find attribute `unknown` in this scope type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK +//~^ ERROR the trait `Copy` cannot be made into an object type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; //~^ ERROR cannot find attribute `unknown` in this scope +//~| ERROR the trait `Copy` cannot be made into an object struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr index 4d6560e96e513..65f428ac8fa93 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr +++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr @@ -5,46 +5,83 @@ LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn(); | ^ error: only lifetime parameters can be used in this context - --> $DIR/cfg-generic-params.rs:11:51 + --> $DIR/cfg-generic-params.rs:12:51 | LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; | ^ error: only lifetime parameters can be used in this context - --> $DIR/cfg-generic-params.rs:15:54 + --> $DIR/cfg-generic-params.rs:17:54 | LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; | ^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:19:29 + --> $DIR/cfg-generic-params.rs:21:29 | LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:22:29 + --> $DIR/cfg-generic-params.rs:24:29 | LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:26:34 + --> $DIR/cfg-generic-params.rs:28:34 | LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:30:40 + --> $DIR/cfg-generic-params.rs:33:40 | LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:34:43 + --> $DIR/cfg-generic-params.rs:38:43 | LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; | ^^^^^^^ -error: aborting due to 8 previous errors +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/cfg-generic-params.rs:10:17 + | +LL | type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(no)] T> Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/cfg-generic-params.rs:12:16 + | +LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/cfg-generic-params.rs:31:15 + | +LL | type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/cfg-generic-params.rs:33:16 + | +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + +error: aborting due to 12 previous errors +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/consts/const-eval/pub_const_err.rs b/src/test/ui/consts/const-eval/pub_const_err.rs index 5faacd556d479..09f0e81c12b80 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.rs +++ b/src/test/ui/consts/const-eval/pub_const_err.rs @@ -7,4 +7,5 @@ pub const Z: u32 = 0 - 1; //~^ WARN any use of this value will cause an error //~| WARN this was previously accepted by the compiler but is being phased out -pub type Foo = [i32; 0 - 1]; +//pub type Foo = [i32; 0 - 1]; +//^ evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.rs b/src/test/ui/consts/const-eval/pub_const_err_bin.rs index 82eae25121e41..654ec6fca4048 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.rs +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.rs @@ -5,6 +5,7 @@ pub const Z: u32 = 0 - 1; //~^ WARN any use of this value will cause an error //~| WARN this was previously accepted by the compiler but is being phased out -pub type Foo = [i32; 0 - 1]; +// pub type Foo = [i32; 0 - 1]; +//^ evaluation of constant value failed fn main() {} diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index 2fd6e060678e9..8d450cb1b9a56 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -17,13 +17,6 @@ const FOO: S = { s }; -type Array = [u32; { - let mut x = 2; - let y = &mut x; //~ ERROR mutable reference - *y = 42; - *y -}]; - fn main() { assert_eq!(FOO.state, 3); } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 3eac61c0ce670..b5fa649405c41 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -16,15 +16,6 @@ LL | s.foo(3); = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:22:13 - | -LL | let y = &mut x; - | ^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_let_assign4.rs b/src/test/ui/consts/const_let_assign4.rs new file mode 100644 index 0000000000000..d422090305da9 --- /dev/null +++ b/src/test/ui/consts/const_let_assign4.rs @@ -0,0 +1,31 @@ +#![feature(const_fn)] + +struct S { + state: u32, +} + +impl S { + const fn foo(&mut self, x: u32) { + self.state = x; + } +} + +const FOO: S = { + let mut s = S { state: 42 }; + s.foo(3); + s +}; +// The `impl` and `const` would error out if the following `type` was correct. +// See `const_let_assignment3.rs`. + +type Array = [u32; { + let mut x = 2; + let y = &mut x; + //~^ ERROR mutable references are not allowed in constants + *y = 42; + *y +}]; + +fn main() { + assert_eq!(FOO.state, 3); +} diff --git a/src/test/ui/consts/const_let_assign4.stderr b/src/test/ui/consts/const_let_assign4.stderr new file mode 100644 index 0000000000000..076cc14b5b2ad --- /dev/null +++ b/src/test/ui/consts/const_let_assign4.stderr @@ -0,0 +1,12 @@ +error[E0658]: mutable references are not allowed in constants + --> $DIR/const_let_assign4.rs:23:13 + | +LL | let y = &mut x; + | ^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +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-trivial_bounds.rs b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs index 3dbaf5dea250e..8521c6983939b 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -15,7 +15,7 @@ trait T where i32: Foo {} //~ ERROR union U where i32: Foo { f: i32 } //~ ERROR -type Y where i32: Foo = (); // OK - bound is ignored +type Y where i32: Foo = (); //~ ERROR impl Foo for () where i32: Foo { //~ ERROR fn test(&self) { diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index f3fa641209563..6055ea6d7e126 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -34,6 +34,15 @@ LL | union U where i32: Foo { f: i32 } = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable +error[E0277]: the trait bound `i32: Foo` is not satisfied + --> $DIR/feature-gate-trivial_bounds.rs:18:25 + | +LL | type Y where i32: Foo = (); + | ^^ the trait `Foo` is not implemented for `i32` + | + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:20:1 | @@ -123,6 +132,6 @@ LL | | } = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs index 0567beab9b9c8..0eb39d8b90eda 100644 --- a/src/test/ui/hygiene/assoc_ty_bindings.rs +++ b/src/test/ui/hygiene/assoc_ty_bindings.rs @@ -5,10 +5,10 @@ trait Base { type AssocTy; - fn f(); + fn f(&self); } trait Derived: Base { - fn g(); + fn g(&self); } macro mac() { @@ -17,12 +17,12 @@ macro mac() { impl Base for u8 { type AssocTy = u8; - fn f() { + fn f(&self) { let _: Self::AssocTy; } } impl Derived for u8 { - fn g() { + fn g(&self) { let _: Self::AssocTy; } } diff --git a/src/test/ui/resolve/issue-3907-2.rs b/src/test/ui/resolve/issue-3907-2.rs index 46f145e63e157..ce16b1224ed73 100644 --- a/src/test/ui/resolve/issue-3907-2.rs +++ b/src/test/ui/resolve/issue-3907-2.rs @@ -2,13 +2,12 @@ extern crate issue_3907; -type Foo = dyn issue_3907::Foo + 'static; +type Foo = dyn issue_3907::Foo + 'static; //~ ERROR E0038 struct S { name: isize } -fn bar(_x: Foo) {} -//~^ ERROR E0038 +fn bar(_x: Foo) {} //~ ERROR E0038 fn main() {} diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr index 782cfeec4bcaf..0b6cd79cb0769 100644 --- a/src/test/ui/resolve/issue-3907-2.stderr +++ b/src/test/ui/resolve/issue-3907-2.stderr @@ -1,3 +1,15 @@ +error[E0038]: the trait `issue_3907::Foo` cannot be made into an object + --> $DIR/issue-3907-2.rs:5:12 + | +LL | type Foo = dyn issue_3907::Foo + 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `issue_3907::Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/auxiliary/issue-3907.rs:2:8 + | +LL | fn bar(); + | ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter + error[E0038]: the trait `issue_3907::Foo` cannot be made into an object --> $DIR/issue-3907-2.rs:11:12 | @@ -10,6 +22,6 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all LL | fn bar(); | ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs index 1e2c4b836a132..52ef0a0bd6070 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.rs +++ b/src/test/ui/structs/struct-path-alias-bounds.rs @@ -3,9 +3,8 @@ struct S { a: T } struct NoClone; -type A = S; +type A = S; //~ ERROR the trait bound `NoClone: Clone` is not satisfied fn main() { let s = A { a: NoClone }; - //~^ ERROR the trait bound `NoClone: Clone` is not satisfied } diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr index cea3d5d4df35d..e01c99ca1910c 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.stderr +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `NoClone: Clone` is not satisfied - --> $DIR/struct-path-alias-bounds.rs:9:13 + --> $DIR/struct-path-alias-bounds.rs:6:10 | LL | struct S { a: T } - | ------------------ required by `S` + | ----- required by this bound in `S` ... -LL | let s = A { a: NoClone }; - | ^ the trait `Clone` is not implemented for `NoClone` +LL | type A = S; + | ^^^^^^^^^^ the trait `Clone` is not implemented for `NoClone` error: aborting due to previous error