From ea7e885204e1ed6b18406e84708abef748925ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Jan 2020 16:12:44 -0800 Subject: [PATCH] Elide E0308 errors in favor of E0746 When a type error involves a `dyn Trait` as the return type, do not emit the type error, as the "return type is not `Sized`" error will provide enough information to the user. --- src/librustc_typeck/check/coercion.rs | 19 ++++- src/librustc_typeck/check/mod.rs | 12 +++ src/test/ui/error-codes/E0746.rs | 5 +- src/test/ui/error-codes/E0746.stderr | 40 +-------- .../dyn-trait-return-should-be-impl-trait.rs | 10 +-- ...n-trait-return-should-be-impl-trait.stderr | 82 ++----------------- 6 files changed, 44 insertions(+), 124 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 698fdfa3897..77f16fb7914 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1222,6 +1222,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; let mut err; + let mut unsized_return = false; match cause.code { ObligationCauseCode::ReturnNoExpression => { err = struct_span_err!( @@ -1243,6 +1244,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { parent_id, expression.map(|expr| (expr, blk_id)), ); + if !fcx.tcx.features().unsized_locals { + unsized_return = fcx.is_unsized_return(blk_id); + } } ObligationCauseCode::ReturnValue(id) => { err = self.report_return_mismatched_types( @@ -1254,6 +1258,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { id, None, ); + if !fcx.tcx.features().unsized_locals { + let id = fcx.tcx.hir().get_parent_node(id); + unsized_return = fcx.is_unsized_return(id); + } } _ => { err = fcx.report_mismatched_types(cause, expected, found, coercion_error); @@ -1282,7 +1290,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty())) .is_some(); - err.emit_unless(assign_to_bool); + if unsized_return { + fcx.tcx.sess.delay_span_bug( + cause.span, + &format!( + "elided E0308 in favor of more detailed E0277 or E0746: {:?}", + cause.code + ), + ); + } + err.emit_unless(assign_to_bool || unsized_return); self.final_ty = Some(fcx.tcx.types.err); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index baf9ae1ac29..8f531ea6199 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4964,6 +4964,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn is_unsized_return(&self, blk_id: hir::HirId) -> bool { + if let Some((fn_decl, _)) = self.get_fn_decl(blk_id) { + if let hir::FunctionRetTy::Return(ty) = fn_decl.output { + let ty = AstConv::ast_ty_to_ty(self, ty); + if let ty::Dynamic(..) = ty.kind { + return true; + } + } + } + false + } + /// A possible error is to forget to add a return type that is needed: /// /// ``` diff --git a/src/test/ui/error-codes/E0746.rs b/src/test/ui/error-codes/E0746.rs index ad257b01e1b..c9ab455a4c5 100644 --- a/src/test/ui/error-codes/E0746.rs +++ b/src/test/ui/error-codes/E0746.rs @@ -5,13 +5,12 @@ impl Trait for u32 {} fn foo() -> dyn Trait { Struct } //~^ ERROR E0746 -//~| ERROR E0308 fn bar() -> dyn Trait { //~ ERROR E0746 if true { - return 0; //~ ERROR E0308 + return 0; } - 42 //~ ERROR E0308 + 42 } fn main() {} diff --git a/src/test/ui/error-codes/E0746.stderr b/src/test/ui/error-codes/E0746.stderr index baafcd27c29..44bd0d7ed7d 100644 --- a/src/test/ui/error-codes/E0746.stderr +++ b/src/test/ui/error-codes/E0746.stderr @@ -1,14 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/E0746.rs:6:25 - | -LL | fn foo() -> dyn Trait { Struct } - | --------- ^^^^^^ expected trait `Trait`, found struct `Struct` - | | - | expected `(dyn Trait + 'static)` because of return type - | - = note: expected trait object `(dyn Trait + 'static)` - found struct `Struct` - error[E0746]: return type cannot have a bare trait because it must be `Sized` --> $DIR/E0746.rs:6:13 | @@ -22,7 +11,7 @@ LL | fn foo() -> impl Trait { Struct } | ^^^^^^^^^^ error[E0746]: return type cannot have a bare trait because it must be `Sized` - --> $DIR/E0746.rs:10:13 + --> $DIR/E0746.rs:9:13 | LL | fn bar() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time @@ -33,30 +22,5 @@ help: you can use the `impl Trait` feature in the return type because all the re LL | fn bar() -> impl Trait { | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/E0746.rs:12:16 - | -LL | fn bar() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -LL | if true { -LL | return 0; - | ^ expected trait `Trait`, found integer - | - = note: expected trait object `(dyn Trait + 'static)` - found type `{integer}` +error: aborting due to 2 previous errors -error[E0308]: mismatched types - --> $DIR/E0746.rs:14:5 - | -LL | fn bar() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -... -LL | 42 - | ^^ expected trait `Trait`, found integer - | - = note: expected trait object `(dyn Trait + 'static)` - found type `{integer}` - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs index 80168ca8257..b70a51dc825 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.rs @@ -12,25 +12,23 @@ fn bar() -> (usize, dyn Trait) { (42, Struct) } //~| ERROR E0308 fn bap() -> Trait { Struct } //~^ ERROR E0746 -//~| ERROR E0308 fn ban() -> dyn Trait { Struct } //~^ ERROR E0746 -//~| ERROR E0308 fn bak() -> dyn Trait { unimplemented!() } //~ ERROR E0277 // Suggest using `Box` fn bal() -> dyn Trait { //~ ERROR E0746 if true { - return Struct; //~ ERROR E0308 + return Struct; } - 42 //~ ERROR E0308 + 42 } // Suggest using `impl Trait` fn bat() -> dyn Trait { //~ ERROR E0746 if true { - return 0; //~ ERROR E0308 + return 0; } - 42 //~ ERROR E0308 + 42 } fn main() {} diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index ce4c141a0af..a09ce2bb298 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -38,17 +38,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:21 - | -LL | fn bap() -> Trait { Struct } - | ----- ^^^^^^ expected trait `Trait`, found struct `Struct` - | | - | expected `(dyn Trait + 'static)` because of return type - | - = note: expected trait object `(dyn Trait + 'static)` - found struct `Struct` - error[E0746]: return type cannot have a bare trait because it must be `Sized` --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13 | @@ -61,19 +50,8 @@ help: you can use the `impl Trait` feature in the return type because all the re LL | fn bap() -> impl Trait { Struct } | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:25 - | -LL | fn ban() -> dyn Trait { Struct } - | --------- ^^^^^^ expected trait `Trait`, found struct `Struct` - | | - | expected `(dyn Trait + 'static)` because of return type - | - = note: expected trait object `(dyn Trait + 'static)` - found struct `Struct` - error[E0746]: return type cannot have a bare trait because it must be `Sized` - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:16:13 + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13 | LL | fn ban() -> dyn Trait { Struct } | ^^^^^^^^^ doesn't have a size known at compile-time @@ -85,7 +63,7 @@ LL | fn ban() -> impl Trait { Struct } | ^^^^^^^^^^ error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13 + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13 | LL | fn bak() -> dyn Trait { unimplemented!() } | ^^^^^^^^^ doesn't have a size known at compile-time @@ -94,26 +72,14 @@ LL | fn bak() -> dyn Trait { unimplemented!() } = note: to learn more, visit = note: the return type of a function must have a statically known size -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:16 - | -LL | fn bal() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -LL | if true { -LL | return Struct; - | ^^^^^^ expected trait `Trait`, found struct `Struct` - | - = note: expected trait object `(dyn Trait + 'static)` - found struct `Struct` - error[E0746]: return type cannot have a bare trait because it must be `Sized` - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:21:13 + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13 | LL | fn bal() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time | help: if all the returned values were of the same type you could use `impl Trait` as the return type - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5 + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:23:5 | LL | return Struct; | ^^^^^^ @@ -132,20 +98,8 @@ LL | } LL | Box::new(42) | -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:25:5 - | -LL | fn bal() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -... -LL | 42 - | ^^ expected trait `Trait`, found integer - | - = note: expected trait object `(dyn Trait + 'static)` - found type `{integer}` - error[E0746]: return type cannot have a bare trait because it must be `Sized` - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:13 + --> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13 | LL | fn bat() -> dyn Trait { | ^^^^^^^^^ doesn't have a size known at compile-time @@ -156,31 +110,7 @@ help: you can use the `impl Trait` feature in the return type because all the re LL | fn bat() -> impl Trait { | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:31:16 - | -LL | fn bat() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -LL | if true { -LL | return 0; - | ^ expected trait `Trait`, found integer - | - = note: expected trait object `(dyn Trait + 'static)` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/dyn-trait-return-should-be-impl-trait.rs:33:5 - | -LL | fn bat() -> dyn Trait { - | --------- expected `(dyn Trait + 'static)` because of return type -... -LL | 42 - | ^^ expected trait `Trait`, found integer - | - = note: expected trait object `(dyn Trait + 'static)` - found type `{integer}` - -error: aborting due to 15 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`.