Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
591584e
Add tests for 'impl Default for [T; N]'
MikailBag May 26, 2020
3313bf6
Skip leak test on targets without panic=unwind
MikailBag May 28, 2020
1bc4e45
Only highlight results via mouseover if mouse has moved
carols10cents Jun 2, 2020
bbb3321
Ensure std benchmarks get tested.
ehuss Jun 8, 2020
724dfba
Clean up some weird command strings
GuillaumeGomez Jun 13, 2020
e32db84
Add rust features to print target features
aszenz Jun 14, 2020
d3ca6fd
Enable static-pie for the x86_64-unknown-linux-musl target
haraldh Jun 15, 2020
9e51008
Complete the std::time documentation to warn about the inconsistencie…
poliorcetics Jun 15, 2020
96f5584
Expand "recursive opaque type" diagnostic
estebank Apr 19, 2020
8f12485
review comments
estebank Jun 15, 2020
268decb
make all uses of ty::Error or ConstKind::Error delay a span bug
mark-i-m May 6, 2020
e855b90
track caller for delay_span_bug
mark-i-m May 26, 2020
5fbef22
warn against 'specialization' feature
RalfJung May 17, 2020
991dfe7
bless all
RalfJung Jun 16, 2020
d1265e7
libcore tests: use min_specialization
RalfJung Jun 16, 2020
1990f97
Disallow loading crates with non-ascii identifier name.
crlf0710 Jun 13, 2020
cfdbbb5
format derives
mark-i-m Jun 16, 2020
4506a35
add header for rust specific feature
aszenz Jun 16, 2020
9f50f84
break long line for formatting
aszenz Jun 16, 2020
457acbd
trim whitespace
aszenz Jun 16, 2020
15cd51a
Mention functions pointers in the documentation
poliorcetics Jun 16, 2020
9f2e8ad
Fix typo in librustc_ast docs
pierwill Jun 17, 2020
e75fa89
Don't imply function pointers are references
poliorcetics Jun 17, 2020
caffb28
add blank line bw sections
aszenz Jun 17, 2020
c9dc73d
Make novel structural match violations a warning
ecstatic-morse Jun 17, 2020
38e921b
Add regression test for #73431
ecstatic-morse Jun 17, 2020
3a1207f
Add issue number to novel violation warning
ecstatic-morse Jun 17, 2020
2da9ca7
Remove duplicate sentence fragment from mem::zeroed doc
dtolnay Jun 18, 2020
4e77214
Improve document for `Result::as_deref(_mut)`
tesuji Jun 18, 2020
09427f6
Rollup merge of #70551 - mark-i-m:ty-err-2, r=varkor
RalfJung Jun 18, 2020
9dfc614
Rollup merge of #70740 - haraldh:static-pie, r=petrochenkov
RalfJung Jun 18, 2020
e9995fe
Rollup merge of #71338 - estebank:recursive-impl-trait, r=nikomatsakis
RalfJung Jun 18, 2020
582b8eb
Rollup merge of #71420 - RalfJung:specialization-incomplete, r=matthe…
RalfJung Jun 18, 2020
594f58e
Rollup merge of #72628 - MikailBag:array-default-tests, r=shepmaster
RalfJung Jun 18, 2020
1a763ea
Rollup merge of #72836 - poliorcetics:std-time-os-specificities, r=sh…
RalfJung Jun 18, 2020
6ca9dce
Rollup merge of #72968 - integer32llc:docs-arrow-keys, r=GuillaumeGomez
RalfJung Jun 18, 2020
d67e993
Rollup merge of #73142 - ehuss:std-benches, r=dtolnay
RalfJung Jun 18, 2020
f8ae9a3
Rollup merge of #73305 - crlf0710:disallow_loading_monsters, r=petroc…
RalfJung Jun 18, 2020
3ff4fac
Rollup merge of #73315 - GuillaumeGomez:clean-up-config-strs, r=kinnison
RalfJung Jun 18, 2020
c51d0ac
Rollup merge of #73346 - aszenz:patch-1, r=cuviper
RalfJung Jun 18, 2020
b87d4a4
Rollup merge of #73425 - poliorcetics:zeroed-functions-pointers, r=dt…
RalfJung Jun 18, 2020
80c2238
Rollup merge of #73428 - pierwill:patch-1, r=jonas-schievink
RalfJung Jun 18, 2020
b3a7b40
Rollup merge of #73446 - ecstatic-morse:issue-73431, r=pnkfelix
RalfJung Jun 18, 2020
e96f154
Rollup merge of #73447 - lzutao:stabilize-result_as_deref, r=dtolnay
RalfJung Jun 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Expand "recursive opaque type" diagnostic
Fix #70968, partially address #66523.
  • Loading branch information
estebank committed Jun 15, 2020
commit 96f5584b808cd08c3c8208db4fee04d2c2b71d79
12 changes: 12 additions & 0 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2726,6 +2726,18 @@ impl Node<'_> {
}
}

pub fn body_id(&self) -> Option<BodyId> {
match self {
Node::TraitItem(TraitItem {
kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
..
})
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
| Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
_ => None,
}
}

pub fn generics(&self) -> Option<&Generics<'_>> {
match self {
Node::TraitItem(TraitItem { generics, .. })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1992,8 +1992,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
/// 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.
#[derive(Default)]
struct ReturnsVisitor<'v> {
returns: Vec<&'v hir::Expr<'v>>,
pub struct ReturnsVisitor<'v> {
pub returns: Vec<&'v hir::Expr<'v>>,
in_block_tail: bool,
}

Expand Down
195 changes: 181 additions & 14 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl};
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
Expand Down Expand Up @@ -1711,6 +1712,181 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
}
}

/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
fn get_owner_return_paths(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
let hir_id = tcx.hir().as_local_hir_id(def_id);
let id = tcx.hir().get_parent_item(hir_id);
tcx.hir()
.find(id)
.map(|n| (id, n))
.and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b)))
.map(|(hir_id, body_id)| {
let body = tcx.hir().body(body_id);
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(body);
(hir_id, visitor)
})
}

/// Emit an error for recursive opaque types.
///
/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
/// `impl Trait`.
///
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
let mut err =
struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type to a concrete type");

let mut label = false;
if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id));
if visitor
.returns
.iter()
.filter_map(|expr| tables.node_type_opt(expr.hir_id))
.map(|ty| tcx.infer_ctxt().enter(|infcx| infcx.resolve_vars_if_possible(&ty)))
.all(|ty| matches!(ty.kind, ty::Never))
{
let spans = visitor
.returns
.iter()
.filter(|expr| tables.node_type_opt(expr.hir_id).is_some())
.map(|expr| expr.span)
.collect::<Vec<Span>>();
let span_len = spans.len();
if span_len == 1 {
err.span_label(spans[0], "this returned value is of `!` type");
} else {
let mut multispan: MultiSpan = spans.clone().into();
for span in spans {
multispan
.push_span_label(span, "this returned value is of `!` type".to_string());
}
err.span_note(multispan, "these returned values have a concrete \"never\" type");
}
err.help("this error will resolve once the item's body returns a concrete type");
} else {
let mut seen = FxHashSet::default();
seen.insert(span);
err.span_label(span, "recursive opaque type");
label = true;
for (sp, ty) in visitor
.returns
.iter()
.filter_map(|e| tables.node_type_opt(e.hir_id).map(|t| (e.span, t)))
.filter(|(_, ty)| !matches!(ty.kind, ty::Never))
.map(|(sp, ty)| {
(sp, tcx.infer_ctxt().enter(|infcx| infcx.resolve_vars_if_possible(&ty)))
})
{
struct VisitTypes(Vec<DefId>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
match t.kind {
ty::Opaque(def, _) => {
self.0.push(def);
false
}
_ => t.super_visit_with(self),
}
}
}
let mut visitor = VisitTypes(vec![]);
ty.visit_with(&mut visitor);
for def_id in visitor.0 {
let ty_span = tcx.def_span(def_id);
if !seen.contains(&ty_span) {
err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
seen.insert(ty_span);
}
err.span_label(sp, &format!("returning here with type `{}`", ty));
}
}
}
}
if !label {
err.span_label(span, "cannot resolve to a concrete type");
}
err.emit();
}

/// Emit an error for recursive opaque types in a `let` binding.
fn binding_opaque_type_cycle_error(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
span: Span,
partially_expanded_type: Ty<'tcx>,
) {
let mut err =
struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type to a concrete type");
err.span_label(span, "cannot resolve to a concrete type");
let hir_id = tcx.hir().as_local_hir_id(def_id);
let mut prev_hir_id = hir_id;
let mut hir_id = tcx.hir().get_parent_node(hir_id);
while let Some(node) = tcx.hir().find(hir_id) {
match node {
hir::Node::Local(hir::Local {
pat,
init: None,
ty: Some(ty),
source: hir::LocalSource::Normal,
..
}) => {
err.span_label(pat.span, "this binding might not have a concrete type");
err.span_suggestion_verbose(
ty.span.shrink_to_hi(),
"set the binding to a value for a concrete type to be resolved",
" = /* value */".to_string(),
Applicability::HasPlaceholders,
);
}
hir::Node::Local(hir::Local {
init: Some(expr),
source: hir::LocalSource::Normal,
..
}) => {
let hir_id = tcx.hir().as_local_hir_id(def_id);
let tables =
tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
let ty = tables.node_type_opt(expr.hir_id);
if let Some(ty) =
tcx.infer_ctxt().enter(|infcx| infcx.resolve_vars_if_possible(&ty))
{
err.span_label(
expr.span,
&format!(
"this is of type `{}`, which doesn't constrain \
`{}` enough to arrive to a concrete type",
ty, partially_expanded_type
),
);
}
}
_ => {}
}
if prev_hir_id == hir_id {
break;
}
prev_hir_id = hir_id;
hir_id = tcx.hir().get_parent_node(hir_id);
}
err.emit();
}

fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
.span_label(span, "recursive `async fn`")
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
.emit();
}

/// Checks that an opaque type does not contain cycles.
fn check_opaque_for_cycles<'tcx>(
tcx: TyCtxt<'tcx>,
Expand All @@ -1721,21 +1897,12 @@ fn check_opaque_for_cycles<'tcx>(
) {
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
{
if let hir::OpaqueTyOrigin::AsyncFn = origin {
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing",)
.span_label(span, "recursive `async fn`")
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
.emit();
} else {
let mut err =
struct_span_err!(tcx.sess, span, E0720, "opaque type expands to a recursive type",);
err.span_label(span, "expands to a recursive type");
if let ty::Opaque(..) = partially_expanded_type.kind {
err.note("type resolves to itself");
} else {
err.note(&format!("expanded type is `{}`", partially_expanded_type));
match origin {
hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
hir::OpaqueTyOrigin::Binding => {
binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
}
err.emit();
_ => opaque_type_cycle_error(tcx, def_id, span),
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/impl-trait/binding-without-value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![allow(incomplete_features)]
#![feature(impl_trait_in_bindings)]

fn foo() {
let _ : impl Copy;
//~^ ERROR cannot resolve opaque type
}

fn main() {}
16 changes: 16 additions & 0 deletions src/test/ui/impl-trait/binding-without-value.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0720]: cannot resolve opaque type to a concrete type
--> $DIR/binding-without-value.rs:5:13
|
LL | let _ : impl Copy;
| - ^^^^^^^^^ cannot resolve to a concrete type
| |
| this binding might not have a concrete type
|
help: set the binding to a value for a concrete type to be resolved
|
LL | let _ : impl Copy = /* value */;
| ^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0720`.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

trait Quux {}

fn foo() -> impl Quux { //~ opaque type expands to a recursive type
fn foo() -> impl Quux { //~ ERROR cannot resolve opaque type
struct Foo<T>(T);
impl<T> Quux for Foo<T> {}
Foo(bar())
}

fn bar() -> impl Quux { //~ opaque type expands to a recursive type
fn bar() -> impl Quux { //~ ERROR cannot resolve opaque type
struct Bar<T>(T);
impl<T> Quux for Bar<T> {}
Bar(foo())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
error[E0720]: opaque type expands to a recursive type
error[E0720]: cannot resolve opaque type to a concrete type
--> $DIR/infinite-impl-trait-issue-38064.rs:8:13
|
LL | fn foo() -> impl Quux {
| ^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `foo::Foo<bar::Bar<impl Quux>>`
| ^^^^^^^^^ recursive opaque type
...
LL | Foo(bar())
| ---------- returning here with type `foo::Foo<impl Quux>`
...
LL | fn bar() -> impl Quux {
| --------- returning this opaque type `foo::Foo<impl Quux>`

error[E0720]: opaque type expands to a recursive type
error[E0720]: cannot resolve opaque type to a concrete type
--> $DIR/infinite-impl-trait-issue-38064.rs:14:13
|
LL | fn foo() -> impl Quux {
| --------- returning this opaque type `bar::Bar<impl Quux>`
...
LL | fn bar() -> impl Quux {
| ^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `bar::Bar<foo::Foo<impl Quux>>`
| ^^^^^^^^^ recursive opaque type
...
LL | Bar(foo())
| ---------- returning here with type `bar::Bar<impl Quux>`

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
error[E0720]: opaque type expands to a recursive type
error[E0720]: cannot resolve opaque type to a concrete type
--> $DIR/recursive-impl-trait-type-direct.rs:5:14
|
LL | fn test() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: type resolves to itself
| ^^^^^^^^^^ recursive opaque type
LL |
LL | test()
| ------ returning here with type `impl Sized`

error: aborting due to previous error

Expand Down
Loading