review comments

This commit is contained in:
Esteban Küber 2020-01-15 11:14:05 -08:00
parent c305ac31c0
commit d7a6212401
8 changed files with 205 additions and 217 deletions

View File

@ -25,7 +25,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::intravisit::Visitor;
use rustc_span::source_map::SourceMap;
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
@ -1411,34 +1410,3 @@ pub fn suggest_constraining_type_param(
}
false
}
/// Collect all the returned expressions within the input expression.
/// Used to point at the return spans when we want to suggest some change to them.
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
type Map = rustc::hir::map::Map<'v>;
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
hir::intravisit::NestedVisitorMap::None
}
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
match ex.kind {
hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
_ => {}
}
hir::intravisit::walk_expr(self, ex);
}
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
if body.generator_kind().is_none() {
if let hir::ExprKind::Block(block, None) = body.value.kind {
if let Some(expr) = block.expr {
self.0.push(expr);
}
}
}
hir::intravisit::walk_body(self, body);
}
}

View File

@ -563,25 +563,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let hir = self.tcx.hir();
let parent_node = hir.get_parent_node(obligation.cause.body_id);
let node = hir.find(parent_node);
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id), ..
let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id),
..
})) = node
{
(sig, body_id)
} else {
return false;
};
let body = hir.body(*body_id);
let trait_ref = self.resolve_vars_if_possible(trait_ref);
let ty = trait_ref.skip_binder().self_ty();
let is_object_safe;
match ty.kind {
let is_object_safe = match ty.kind {
ty::Dynamic(predicates, _) => {
// The `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
is_object_safe = predicates.principal_def_id().map_or(true, |def_id| {
!object_safety_violations(self.tcx, def_id).is_empty()
})
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
predicates
.principal_def_id()
.map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty())
}
// We only want to suggest `impl Trait` to `dyn Trait`s.
// For example, `fn foo() -> str` needs to be filtered out.
_ => return false,
}
};
let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
ret_ty
@ -702,18 +706,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
trait_obj,
));
}
err.note(trait_obj_msg);
err.note(&format!(
"if all the returned values were of the same type you could use \
`impl {}` as the return type",
trait_obj,
));
err.note(impl_trait_msg);
err.note(trait_obj_msg);
err.note("you can create a new `enum` with a variant for each returned type");
}
return true;
}
false
true
}
crate fn point_at_returns_when_relevant(
@ -1686,6 +1688,8 @@ pub fn suggest_constraining_type_param(
false
}
/// Collect all the returned expressions within the input expression.
/// Used to point at the return spans when we want to suggest some change to them.
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {

View File

@ -1171,7 +1171,7 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
impl<'tcx> ObligationCauseCode<'tcx> {
impl ObligationCauseCode<'_> {
// Return the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;

View File

@ -12,8 +12,8 @@ impl T for S {
fn bar(&self) {}
}
// Having the trait `T` as return type is invalid because bare traits do not
// have a statically known size:
// Having the trait `T` as return type is invalid because
// bare trait objects do not have a statically known size:
fn foo() -> dyn T {
S(42)
}
@ -32,15 +32,15 @@ If there is a single type involved, you can use [`impl Trait`]:
# fn bar(&self) {}
# }
// The compiler will select `S(usize)` as the materialized return type of this
// function, but callers will only be able to access associated items from `T`.
// function, but callers will only know that the return type implements `T`.
fn foo() -> impl T {
S(42)
}
```
If there are multiple types involved, the only way you care to interact with
them is through the trait's interface and having to rely on dynamic dispatch is
acceptable, then you can use [trait objects] with `Box`, or other container
them is through the trait's interface, and having to rely on dynamic dispatch
is acceptable, then you can use [trait objects] with `Box`, or other container
types like `Rc` or `Arc`:
```

View File

@ -68,7 +68,7 @@ use rustc_error_codes::*;
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span;
use rustc_span::{self, Span};
use rustc_span::symbol::sym;
use rustc_target::spec::abi::Abi;
use smallvec::{smallvec, SmallVec};
@ -1352,12 +1352,32 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, return_sp);
}
err
}
fn add_impl_trait_explanation<'a>(
&self,
err: &mut DiagnosticBuilder<'a>,
fcx: &FnCtxt<'a, 'tcx>,
expected: Ty<'tcx>,
sp: Span,
return_sp: Span,
) {
err.span_label(return_sp, "expected because this return type...");
err.span_label( *sp, format!(
"...is found to be `{}` here",
fcx.resolve_vars_with_obligations(expected),
));
err.span_label(
sp,
format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)),
);
let impl_trait_msg = "for information on `impl Trait`, see \
<https://doc.rust-lang.org/book/ch10-02-traits.html\
#returning-types-that-implement-traits>";
let trait_obj_msg = "for information on trait objects, see \
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
#using-trait-objects-that-allow-for-values-of-different-types>";
err.note("to return `impl Trait`, all returned values must be of the same type");
err.note(impl_trait_msg);
let snippet = fcx
.tcx
.sess
@ -1371,20 +1391,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
"you can instead return a trait object using `Box<dyn {}>`",
&snippet[5..]
));
}
err.help("alternatively, create a new `enum` with a variant for each returned type");
let impl_trait_msg = "for information on `impl Trait`, see \
<https://doc.rust-lang.org/book/ch10-02-traits.html\
#returning-types-that-implement-traits>";
let trait_obj_msg = "for information on trait objects, see \
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
#using-trait-objects-that-allow-for-values-of-different-types>";
err.note(impl_trait_msg);
if has_impl {
err.note(trait_obj_msg);
}
}
err
err.help("alternatively, create a new `enum` with a variant for each returned type");
}
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {

View File

@ -82,11 +82,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bal() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
= note: if trait `Trait` was object safe, you could return a trait object
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= note: if all the returned values were of the same type you could use `impl Trait` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= note: you can create a new `enum` with a variant for each returned type
help: return a trait object instead
|
LL | fn bal() -> Box<dyn Trait> {
LL | if true {
LL | return Box::new(Struct);
LL | }
LL | Box::new(42)
|
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13

View File

@ -11,10 +11,10 @@ LL | 0_u32
| ^^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn Foo>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn Foo>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:24:11

View File

@ -11,10 +11,10 @@ LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
@ -29,10 +29,10 @@ LL | return 1u32;
| ^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
@ -47,10 +47,10 @@ LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
@ -77,10 +77,10 @@ LL | _ => 1u32,
| ^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
@ -97,10 +97,10 @@ LL | | }
| |_____^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
@ -115,10 +115,10 @@ LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
= note: to return `impl Trait`, all returned values must be of the same type
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= help: alternatively, create a new `enum` with a variant for each returned type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
= help: alternatively, create a new `enum` with a variant for each returned type
error: aborting due to 7 previous errors