From bdcace0eb4a8e80044d582e5f44d5f00fe9468da Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 18 Jun 2018 13:44:36 +0200 Subject: [PATCH 01/18] Cleanup in preparation of generic extraction --- src/librustc/hir/lowering.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 110ebf6b215a1..3350b046c97d5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1364,8 +1364,9 @@ impl<'a> LoweringContext<'a> { } fn visit_ty(&mut self, t: &'v hir::Ty) { + match t.node { // Don't collect elided lifetimes used inside of `fn()` syntax - if let &hir::Ty_::TyBareFn(_) = &t.node { + hir::Ty_::TyBareFn(_) => { let old_collect_elided_lifetimes = self.collect_elided_lifetimes; self.collect_elided_lifetimes = false; @@ -1376,8 +1377,8 @@ impl<'a> LoweringContext<'a> { self.currently_bound_lifetimes.truncate(old_len); self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - hir::intravisit::walk_ty(self, t); + }, + _ => hir::intravisit::walk_ty(self, t), } } From b2e2c321053a1bed9dd3ebf02e440072d797f3e3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 18 Jun 2018 16:23:13 +0200 Subject: [PATCH 02/18] Generate the `NodeId` for `existential type` in the AST --- src/librustc/hir/lowering.rs | 54 +++++++++++++++++---------- src/librustc_driver/pretty.rs | 2 +- src/librustc_passes/ast_validation.rs | 6 +-- src/librustc_save_analysis/sig.rs | 2 +- src/libsyntax/ast.rs | 6 ++- src/libsyntax/fold.rs | 4 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/visit.rs | 2 +- 9 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3350b046c97d5..d8d222b9a39f7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1167,12 +1167,14 @@ impl<'a> LoweringContext<'a> { } hir::TyTraitObject(bounds, lifetime_bound) } - TyKind::ImplTrait(ref bounds) => { + TyKind::ImplTrait(exist_ty_node_id, ref bounds) => { let span = t.span; match itctx { ImplTraitContext::Existential(fn_def_id) => { self.lower_existential_impl_trait( - span, fn_def_id, |this| this.lower_param_bounds(bounds, itctx)) + span, fn_def_id, exist_ty_node_id, + |this| this.lower_param_bounds(bounds, itctx), + ) } ImplTraitContext::Universal(def_id) => { let def_node_id = self.next_id().node_id; @@ -1240,13 +1242,9 @@ impl<'a> LoweringContext<'a> { &mut self, span: Span, fn_def_id: DefId, + exist_ty_node_id: NodeId, lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::GenericBounds, ) -> hir::Ty_ { - // We need to manually repeat the code of `next_id` because the lowering - // needs to happen while the owner_id is pointing to the item itself, - // because items are their own owners - let exist_ty_node_id = self.sess.next_node_id(); - // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop // desugaring that explicitly states that we don't want to track that. @@ -1365,18 +1363,18 @@ impl<'a> LoweringContext<'a> { fn visit_ty(&mut self, t: &'v hir::Ty) { match t.node { - // Don't collect elided lifetimes used inside of `fn()` syntax + // Don't collect elided lifetimes used inside of `fn()` syntax hir::Ty_::TyBareFn(_) => { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - hir::intravisit::walk_ty(self, t); - self.currently_bound_lifetimes.truncate(old_len); + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + hir::intravisit::walk_ty(self, t); + self.currently_bound_lifetimes.truncate(old_len); - self.collect_elided_lifetimes = old_collect_elided_lifetimes; + self.collect_elided_lifetimes = old_collect_elided_lifetimes; }, _ => hir::intravisit::walk_ty(self, t), } @@ -3093,12 +3091,28 @@ impl<'a> LoweringContext<'a> { ItemKind::Use(ref use_tree) => { let mut vec = SmallVector::one(hir::ItemId { id: i.id }); self.lower_item_id_use_tree(use_tree, i.id, &mut vec); - return vec; + vec } - ItemKind::MacroDef(..) => return SmallVector::new(), - _ => {} + ItemKind::MacroDef(..) => SmallVector::new(), + ItemKind::Fn(ref decl, ..) => { + struct IdVisitor { ids: SmallVector } + impl<'a> Visitor<'a> for IdVisitor { + fn visit_ty(&mut self, ty: &'a Ty) { + if let TyKind::ImplTrait(id, _) = ty.node { + self.ids.push(hir::ItemId { id }); + } + visit::walk_ty(self, ty); + } + } + let mut visitor = IdVisitor { ids: SmallVector::one(hir::ItemId { id: i.id }) }; + match decl.output { + FunctionRetTy::Default(_) => {}, + FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty), + } + visitor.ids + }, + _ => SmallVector::one(hir::ItemId { id: i.id }), } - SmallVector::one(hir::ItemId { id: i.id }) } fn lower_item_id_use_tree(&mut self, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 38ecbf5ca8ada..711bcfbde2c6f 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -669,7 +669,7 @@ impl<'a> ReplaceBodyWithLoop<'a> { if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output { fn involves_impl_trait(ty: &ast::Ty) -> bool { match ty.node { - ast::TyKind::ImplTrait(_) => true, + ast::TyKind::ImplTrait(..) => true, ast::TyKind::Slice(ref subty) | ast::TyKind::Array(ref subty, _) | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) | diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 25187032fb473..97140d18c0865 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -208,7 +208,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.no_questions_in_bounds(bounds, "trait object types", false); } - TyKind::ImplTrait(ref bounds) => { + TyKind::ImplTrait(_, ref bounds) => { if !bounds.iter() .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { self.err_handler().span_err(ty.span, "at least one trait must be specified"); @@ -505,7 +505,7 @@ impl<'a> NestedImplTraitVisitor<'a> { impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { fn visit_ty(&mut self, t: &'a Ty) { - if let TyKind::ImplTrait(_) = t.node { + if let TyKind::ImplTrait(..) = t.node { if let Some(outer_impl_trait) = self.outer_impl_trait { struct_span_err!(self.session, t.span, E0666, "nested `impl Trait` is not allowed") @@ -570,7 +570,7 @@ impl<'a> ImplTraitProjectionVisitor<'a> { impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { fn visit_ty(&mut self, t: &'a Ty) { match t.node { - TyKind::ImplTrait(_) => { + TyKind::ImplTrait(..) => { if self.is_banned { struct_span_err!(self.session, t.span, E0667, "`impl Trait` is not allowed in path parameters") diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 9f2ca20276cdc..70feba1eff866 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -306,7 +306,7 @@ impl Sig for ast::Ty { let nested = pprust::bounds_to_string(bounds); Ok(text_sig(nested)) } - ast::TyKind::ImplTrait(ref bounds) => { + ast::TyKind::ImplTrait(_, ref bounds) => { // FIXME recurse into bounds let nested = pprust::bounds_to_string(bounds); Ok(text_sig(format!("impl {}", nested))) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 53465c071f33a..ca07ac7988dfe 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1547,7 +1547,11 @@ pub enum TyKind { TraitObject(GenericBounds, TraitObjectSyntax), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. - ImplTrait(GenericBounds), + /// + /// The `NodeId` exists to prevent lowering from having to + /// generate `NodeId`s on the fly, which would complicate + /// the generation of `existential type` items significantly + ImplTrait(NodeId, GenericBounds), /// No-op; kept solely so that we can pretty-print faithfully Paren(P), /// Unused for now diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 712d00fde32db..1035be3a15979 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -396,8 +396,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyKind::TraitObject(bounds, syntax) => { TyKind::TraitObject(bounds.move_map(|b| fld.fold_param_bound(b)), syntax) } - TyKind::ImplTrait(bounds) => { - TyKind::ImplTrait(bounds.move_map(|b| fld.fold_param_bound(b))) + TyKind::ImplTrait(id, bounds) => { + TyKind::ImplTrait(fld.new_id(id), bounds.move_map(|b| fld.fold_param_bound(b))) } TyKind::Mac(mac) => { TyKind::Mac(fld.fold_mac(mac)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 21bd6c083244d..8690918c80525 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1537,7 +1537,7 @@ impl<'a> Parser<'a> { // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::ImplTrait(bounds) + TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) } else if self.check_keyword(keywords::Dyn) && self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3359225e15965..74edf538842c6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1078,7 +1078,7 @@ impl<'a> State<'a> { let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" }; self.print_type_bounds(prefix, &bounds[..])?; } - ast::TyKind::ImplTrait(ref bounds) => { + ast::TyKind::ImplTrait(_, ref bounds) => { self.print_type_bounds("impl", &bounds[..])?; } ast::TyKind::Array(ref ty, ref length) => { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 41e3ad9d4f4b1..bb35bcee43806 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -338,7 +338,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { visitor.visit_anon_const(length) } TyKind::TraitObject(ref bounds, ..) | - TyKind::ImplTrait(ref bounds) => { + TyKind::ImplTrait(_, ref bounds) => { walk_list!(visitor, visit_param_bound, bounds); } TyKind::Typeof(ref expression) => { From f8e83a606264c66020d6f08be8b1dfbc2a5ebda9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 20 Jun 2018 10:44:31 +0200 Subject: [PATCH 03/18] Don't generate a new NodeId for universal impl Trait --- src/librustc/hir/lowering.rs | 7 +++---- src/librustc/hir/map/collector.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d8d222b9a39f7..18f652854d87b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1167,18 +1167,17 @@ impl<'a> LoweringContext<'a> { } hir::TyTraitObject(bounds, lifetime_bound) } - TyKind::ImplTrait(exist_ty_node_id, ref bounds) => { + TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { ImplTraitContext::Existential(fn_def_id) => { self.lower_existential_impl_trait( - span, fn_def_id, exist_ty_node_id, + span, fn_def_id, def_node_id, |this| this.lower_param_bounds(bounds, itctx), ) } ImplTraitContext::Universal(def_id) => { - let def_node_id = self.next_id().node_id; - + self.lower_node_id(def_node_id); // Add a definition for the in-band TyParam let def_index = self.resolver.definitions().create_def_with_parent( def_id.index, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 14cecba490d0a..f16bf1d774455 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -221,9 +221,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. if cfg!(debug_assertions) { - let hir_id_owner = self.definitions.node_to_hir_id(id).owner; + let hir_id = self.definitions.node_to_hir_id(id); - if hir_id_owner != self.current_dep_node_owner { + if hir_id.owner != self.current_dep_node_owner { let node_str = match self.definitions.opt_def_index(id) { Some(def_index) => { self.definitions.def_path(def_index).to_string_no_crate() @@ -231,13 +231,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { None => format!("{:?}", node) }; + if hir_id == ::hir::DUMMY_HIR_ID { + println!("Maybe you forgot to lower the node id {:?}?", id); + } + bug!("inconsistent DepNode for `{}`: \ current_dep_node_owner={}, hir_id.owner={}", node_str, self.definitions .def_path(self.current_dep_node_owner) .to_string_no_crate(), - self.definitions.def_path(hir_id_owner).to_string_no_crate()) + self.definitions.def_path(hir_id.owner).to_string_no_crate()) } } From 013fca8698eb858b19c0a2c31fa1f1487b1e582d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 20 Jun 2018 10:59:24 +0200 Subject: [PATCH 04/18] Generate `DefId`s for impl Trait in the def_collector --- src/librustc/hir/lowering.rs | 25 ++++++++----------------- src/librustc/hir/map/def_collector.rs | 3 +++ src/librustc/hir/map/definitions.rs | 12 ++++-------- src/librustc/ty/item_path.rs | 3 +-- src/librustc/util/ppaux.rs | 3 +-- 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 18f652854d87b..a21d2b6913510 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1179,14 +1179,11 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::Universal(def_id) => { self.lower_node_id(def_node_id); // Add a definition for the in-band TyParam - let def_index = self.resolver.definitions().create_def_with_parent( - def_id.index, - def_node_id, - DefPathData::UniversalImplTrait, - DefIndexAddressSpace::High, - Mark::root(), - span, - ); + let def_index = self + .resolver + .definitions() + .opt_def_index(def_node_id) + .unwrap(); let hir_bounds = self.lower_param_bounds(bounds, itctx); // Set the name to `impl Bound1 + Bound2` @@ -1254,18 +1251,12 @@ impl<'a> LoweringContext<'a> { span, ); - // Pull a new definition from the ether let exist_ty_def_index = self .resolver .definitions() - .create_def_with_parent( - fn_def_id.index, - exist_ty_node_id, - DefPathData::ExistentialImplTrait, - DefIndexAddressSpace::High, - Mark::root(), - exist_ty_span, - ); + .opt_def_index(exist_ty_node_id) + .unwrap(); + self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait"); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 7c71401c8b2e8..4884d4407577a 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -302,6 +302,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { TyKind::Mac(..) => return self.visit_macro_invoc(ty.id), + TyKind::ImplTrait(node_id, _) => { + self.create_def(node_id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span); + } _ => {} } visit::walk_ty(self, ty); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index b2365e22cc66f..ca2789f04f2e2 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -374,10 +374,8 @@ pub enum DefPathData { StructCtor, /// A constant expression (see {ast,hir}::AnonConst). AnonConst, - /// An `impl Trait` type node in argument position. - UniversalImplTrait, - /// An `impl Trait` type node in return position. - ExistentialImplTrait, + /// An `impl Trait` type node + ImplTrait, /// GlobalMetaData identifies a piece of crate metadata that is global to /// a whole crate (as opposed to just one item). GlobalMetaData components @@ -641,8 +639,7 @@ impl DefPathData { ClosureExpr | StructCtor | AnonConst | - ExistentialImplTrait | - UniversalImplTrait => None + ImplTrait => None } } @@ -672,8 +669,7 @@ impl DefPathData { ClosureExpr => "{{closure}}", StructCtor => "{{constructor}}", AnonConst => "{{constant}}", - ExistentialImplTrait => "{{exist-impl-Trait}}", - UniversalImplTrait => "{{univ-impl-Trait}}", + ImplTrait => "{{impl-Trait}}", }; Symbol::intern(s).as_interned_str() diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 479fbe2673b97..95da68bc9ffc2 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -221,8 +221,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::AnonConst | data @ DefPathData::MacroDef(..) | data @ DefPathData::ClosureExpr | - data @ DefPathData::ExistentialImplTrait | - data @ DefPathData::UniversalImplTrait | + data @ DefPathData::ImplTrait | data @ DefPathData::GlobalMetaData(..) => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4fe9c34c140cb..24bda3a47442a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -291,8 +291,7 @@ impl PrintContext { DefPathData::Field(_) | DefPathData::StructCtor | DefPathData::AnonConst | - DefPathData::ExistentialImplTrait | - DefPathData::UniversalImplTrait | + DefPathData::ImplTrait | DefPathData::GlobalMetaData(_) => { // if we're making a symbol for something, there ought // to be a value or type-def or something in there From 1b202426dcac3febc06b89a9ceecc8eb47db59e8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 25 Jun 2018 17:50:51 +0200 Subject: [PATCH 05/18] fixup --- src/test/ui/impl-trait/auto-trait-leak.stderr | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 490817c46f811..acb1a0557be95 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,12 +1,18 @@ -error[E0391]: cycle detected when processing `cycle1` +error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` + --> $DIR/auto-trait-leak.rs:24:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:24:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{exist-impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:31:16 +note: ...which requires processing `cycle2::{{impl-Trait}}`... + --> $DIR/auto-trait-leak.rs:33:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ @@ -16,13 +22,45 @@ note: ...which requires processing `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle1::{{exist-impl-Trait}}`... + = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + +error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` --> $DIR/auto-trait-leak.rs:24:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ - = note: ...which again requires processing `cycle1`, completing the cycle -note: cycle used when type-checking all item bodies + | +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:24:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... +note: ...which requires processing `cycle2::{{impl-Trait}}`... + --> $DIR/auto-trait-leak.rs:33:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:33:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + +error[E0277]: `std::rc::Rc` cannot be sent between threads safely + --> $DIR/auto-trait-leak.rs:27:5 + | +LL | send(cycle2().clone()); + | ^^^^ `std::rc::Rc` cannot be sent between threads safely + | + = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = note: required because it appears within the type `impl std::clone::Clone` +note: required by `send` + --> $DIR/auto-trait-leak.rs:16:1 + | +LL | fn send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From 2ec5eab368b3320950007b07b00600b9a981827a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 22 Jun 2018 12:03:44 +0200 Subject: [PATCH 06/18] Also place method impl trait into the surrounding module --- src/librustc/hir/lowering.rs | 62 ++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a21d2b6913510..b7260dded920e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3076,6 +3076,45 @@ impl<'a> LoweringContext<'a> { } } + /// Lowers `impl Trait` items and appends them to the list + fn lower_impl_trait_ids( + &mut self, + decl: &FnDecl, + ids: &mut SmallVector, + ) { + struct IdVisitor<'a> { ids: &'a mut SmallVector } + impl<'a, 'b> Visitor<'a> for IdVisitor<'b> { + fn visit_ty(&mut self, ty: &'a Ty) { + match ty.node { + | TyKind::Typeof(_) + | TyKind::BareFn(_) + => return, + + TyKind::ImplTrait(id, _) => self.ids.push(hir::ItemId { id }), + _ => {}, + } + visit::walk_ty(self, ty); + } + fn visit_path_segment( + &mut self, + path_span: Span, + path_segment: &'v PathSegment, + ) { + if let Some(ref p) = path_segment.parameters { + if let PathParameters::Parenthesized(..) = **p { + return; + } + } + visit::walk_path_segment(self, path_span, path_segment) + } + } + let mut visitor = IdVisitor { ids }; + match decl.output { + FunctionRetTy::Default(_) => {}, + FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty), + } + } + fn lower_item_id(&mut self, i: &Item) -> SmallVector { match i.node { ItemKind::Use(ref use_tree) => { @@ -3085,21 +3124,18 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) => SmallVector::new(), ItemKind::Fn(ref decl, ..) => { - struct IdVisitor { ids: SmallVector } - impl<'a> Visitor<'a> for IdVisitor { - fn visit_ty(&mut self, ty: &'a Ty) { - if let TyKind::ImplTrait(id, _) = ty.node { - self.ids.push(hir::ItemId { id }); - } - visit::walk_ty(self, ty); + let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + self.lower_impl_trait_ids(decl, &mut ids); + ids + }, + ItemKind::Impl(.., ref items) => { + let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + for item in items { + if let ImplItemKind::Method(ref sig, _) = item.node { + self.lower_impl_trait_ids(&sig.decl, &mut ids); } } - let mut visitor = IdVisitor { ids: SmallVector::one(hir::ItemId { id: i.id }) }; - match decl.output { - FunctionRetTy::Default(_) => {}, - FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty), - } - visitor.ids + ids }, _ => SmallVector::one(hir::ItemId { id: i.id }), } From 9eb75613f0425743933612b59e65d22596af5165 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 11:56:24 +0200 Subject: [PATCH 07/18] Generate `DefId`s for the impl trait of `async` functions --- src/librustc/hir/lowering.rs | 71 +++++++++++++++++---------- src/librustc/hir/map/def_collector.rs | 22 ++++++--- src/librustc_resolve/lib.rs | 9 ++-- src/libsyntax/ast.rs | 7 ++- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/fold.rs | 31 ++++++++---- src/libsyntax/parse/parser.rs | 16 +++--- 7 files changed, 102 insertions(+), 56 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7260dded920e..004121147d904 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -863,7 +863,7 @@ impl<'a> LoweringContext<'a> { let capture_clause = self.lower_capture_clause(capture_clause); let closure_hir_id = self.lower_node_id(closure_node_id).hir_id; - let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, false); + let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None); let generator = hir::Expr { id: closure_node_id, hir_id: closure_hir_id, @@ -1106,7 +1106,7 @@ impl<'a> LoweringContext<'a> { ), unsafety: this.lower_unsafety(f.unsafety), abi: f.abi, - decl: this.lower_fn_decl(&f.decl, None, false, false), + decl: this.lower_fn_decl(&f.decl, None, false, None), arg_names: this.lower_fn_args_to_names(&f.decl), })) }, @@ -1176,7 +1176,7 @@ impl<'a> LoweringContext<'a> { |this| this.lower_param_bounds(bounds, itctx), ) } - ImplTraitContext::Universal(def_id) => { + ImplTraitContext::Universal(_def_id) => { self.lower_node_id(def_node_id); // Add a definition for the in-band TyParam let def_index = self @@ -1866,18 +1866,18 @@ impl<'a> LoweringContext<'a> { // decl: the unlowered (ast) function declaration. // fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the // given DefId, otherwise impl Trait is disallowed. Must be `Some` if - // make_ret_async is true. + // make_ret_async is also `Some`. // impl_trait_return_allow: determines whether impl Trait can be used in return position. // This guards against trait declarations and implementations where impl Trait is // disallowed. - // make_ret_async: if enabled, converts `-> T` into `-> impl Future` in the + // make_ret_async: if `Some`, converts `-> T` into `-> impl Future` in the // return type. This is used for `async fn` declarations. fn lower_fn_decl( &mut self, decl: &FnDecl, fn_def_id: Option, impl_trait_return_allow: bool, - make_ret_async: bool, + make_ret_async: Option, ) -> P { let inputs = decl.inputs .iter() @@ -1890,9 +1890,9 @@ impl<'a> LoweringContext<'a> { }) .collect::>(); - let output = if make_ret_async { + let output = if let Some(ret_id) = make_ret_async { self.lower_async_fn_ret_ty( - &inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id")) + &inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id"), ret_id) } else { match decl.output { FunctionRetTy::Ty(ref ty) => match fn_def_id { @@ -1928,6 +1928,7 @@ impl<'a> LoweringContext<'a> { inputs: &[P], output: &FunctionRetTy, fn_def_id: DefId, + return_impl_trait_id: NodeId, ) -> hir::FunctionRetTy { // Get lifetimes used in the input arguments to the function. Our output type must also // have the same lifetime. FIXME(cramertj) multiple different lifetimes are not allowed @@ -2079,7 +2080,7 @@ impl<'a> LoweringContext<'a> { }; let impl_trait_ty = self.lower_existential_impl_trait( - span, fn_def_id, |this| { + span, fn_def_id, return_impl_trait_id, |this| { let output_ty = match output { FunctionRetTy::Ty(ty) => this.lower_ty(ty, ImplTraitContext::Existential(fn_def_id)), @@ -2564,9 +2565,9 @@ impl<'a> LoweringContext<'a> { // only cares about the input argument patterns in the function // declaration (decl), not the return types. let body_id = this.lower_body(Some(decl), |this| { - if let IsAsync::Async(async_node_id) = header.asyncness { + if let IsAsync::Async { closure_id, .. } = header.asyncness { let async_expr = this.make_async_expr( - CaptureBy::Value, async_node_id, None, + CaptureBy::Value, closure_id, None, |this| { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) @@ -2578,12 +2579,17 @@ impl<'a> LoweringContext<'a> { } }); + let asyncness = match header.asyncness { + IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), + IsAsync::NotAsync => None, + }; + let (generics, fn_decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, |this| this.lower_fn_decl( - decl, Some(fn_def_id), true, header.asyncness.is_async()) + decl, Some(fn_def_id), true, asyncness) ); hir::ItemFn( @@ -2906,7 +2912,7 @@ impl<'a> LoweringContext<'a> { AnonymousLifetimeMode::PassThrough, |this| { hir::TraitItemKind::Method( - this.lower_method_sig(sig, trait_item_def_id, false, false), + this.lower_method_sig(sig, trait_item_def_id, false, None), hir::TraitMethod::Required(names), ) }, @@ -2924,7 +2930,7 @@ impl<'a> LoweringContext<'a> { AnonymousLifetimeMode::PassThrough, |this| { hir::TraitItemKind::Method( - this.lower_method_sig(sig, trait_item_def_id, false, false), + this.lower_method_sig(sig, trait_item_def_id, false, None), hir::TraitMethod::Provided(body_id), ) }, @@ -2995,9 +3001,9 @@ impl<'a> LoweringContext<'a> { } ImplItemKind::Method(ref sig, ref body) => { let body_id = self.lower_body(Some(&sig.decl), |this| { - if let IsAsync::Async(async_node_id) = sig.header.asyncness { + if let IsAsync::Async { closure_id, .. } = sig.header.asyncness { let async_expr = this.make_async_expr( - CaptureBy::Value, async_node_id, None, + CaptureBy::Value, closure_id, None, |this| { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) @@ -3010,6 +3016,11 @@ impl<'a> LoweringContext<'a> { }); let impl_trait_return_allow = !self.is_in_trait_impl; + let asyncness = match sig.header.asyncness { + IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), + IsAsync::NotAsync => None, + }; + self.add_in_band_defs( &i.generics, impl_item_def_id, @@ -3020,7 +3031,7 @@ impl<'a> LoweringContext<'a> { sig, impl_item_def_id, impl_trait_return_allow, - sig.header.asyncness.is_async(), + asyncness, ), body_id, ) @@ -3100,8 +3111,8 @@ impl<'a> LoweringContext<'a> { path_span: Span, path_segment: &'v PathSegment, ) { - if let Some(ref p) = path_segment.parameters { - if let PathParameters::Parenthesized(..) = **p { + if let Some(ref p) = path_segment.args { + if let GenericArgs::Parenthesized(_) = **p { return; } } @@ -3123,8 +3134,11 @@ impl<'a> LoweringContext<'a> { vec } ItemKind::MacroDef(..) => SmallVector::new(), - ItemKind::Fn(ref decl, ..) => { + ItemKind::Fn(ref decl, ref header, ..) => { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + if let IsAsync::Async { return_impl_trait_id, .. } = header.asyncness { + ids.push(hir::ItemId { id: return_impl_trait_id }); + } self.lower_impl_trait_ids(decl, &mut ids); ids }, @@ -3132,6 +3146,9 @@ impl<'a> LoweringContext<'a> { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { + if let IsAsync::Async { return_impl_trait_id, .. } = sig.header.asyncness { + ids.push(hir::ItemId { id: return_impl_trait_id }); + } self.lower_impl_trait_ids(&sig.decl, &mut ids); } } @@ -3214,7 +3231,7 @@ impl<'a> LoweringContext<'a> { |this| { ( // Disallow impl Trait in foreign items - this.lower_fn_decl(fdec, None, false, false), + this.lower_fn_decl(fdec, None, false, None), this.lower_fn_args_to_names(fdec), ) }, @@ -3238,7 +3255,7 @@ impl<'a> LoweringContext<'a> { sig: &MethodSig, fn_def_id: DefId, impl_trait_return_allow: bool, - is_async: bool, + is_async: Option, ) -> hir::MethodSig { hir::MethodSig { header: self.lower_fn_header(sig.header), @@ -3278,7 +3295,7 @@ impl<'a> LoweringContext<'a> { fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync { match a { - IsAsync::Async(_) => hir::IsAsync::Async, + IsAsync::Async { .. } => hir::IsAsync::Async, IsAsync::NotAsync => hir::IsAsync::NotAsync, } } @@ -3581,7 +3598,7 @@ impl<'a> LoweringContext<'a> { ExprKind::Closure( capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span ) => { - if let IsAsync::Async(async_closure_node_id) = asyncness { + if let IsAsync::Async { async_closure_node_id, .. } = asyncness { let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FunctionRetTy::Default(fn_decl_span), @@ -3590,7 +3607,7 @@ impl<'a> LoweringContext<'a> { // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, false, false); + let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); self.with_new_scopes(|this| { // FIXME(cramertj) allow `async` non-`move` closures with @@ -3617,7 +3634,7 @@ impl<'a> LoweringContext<'a> { Some(&**ty) } else { None }; let async_body = this.make_async_expr( - capture_clause, async_closure_node_id, async_ret_ty, + capture_clause, closure_id, async_ret_ty, |this| { this.with_new_scopes(|this| this.lower_expr(body)) }); @@ -3633,7 +3650,7 @@ impl<'a> LoweringContext<'a> { }) } else { // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, false, false); + let fn_decl = self.lower_fn_decl(decl, None, false, None); self.with_new_scopes(|this| { let mut is_generator = false; diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 4884d4407577a..47ebc97310213 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -77,6 +77,7 @@ impl<'a> DefCollector<'a> { &mut self, id: NodeId, async_node_id: NodeId, + return_impl_trait_id: NodeId, name: Name, span: Span, visit_fn: impl FnOnce(&mut DefCollector<'a>) @@ -86,6 +87,7 @@ impl<'a> DefCollector<'a> { let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span); return self.with_parent(fn_def, |this| { + this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span); let closure_def = this.create_def(async_node_id, DefPathData::ClosureExpr, REGULAR_SPACE, @@ -120,10 +122,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } - ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => { + ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async { + closure_id, + return_impl_trait_id, + }, .. }, ..) => { return self.visit_async_fn( i.id, - async_node_id, + closure_id, + return_impl_trait_id, i.ident.name, i.span, |this| visit::walk_item(this, i) @@ -228,11 +234,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(MethodSig { - header: FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, .. + header: FnHeader { asyncness: IsAsync::Async { + closure_id, + return_impl_trait_id, + }, .. }, .. }, ..) => { return self.visit_async_fn( ii.id, - async_node_id, + closure_id, + return_impl_trait_id, ii.ident.name, ii.span, |this| visit::walk_impl_item(this, ii) @@ -277,8 +287,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // Async closures desugar to closures inside of closures, so // we must create two defs. - if let IsAsync::Async(async_id) = asyncness { - let async_def = self.create_def(async_id, + if let IsAsync::Async { closure_id, .. } = asyncness { + let async_def = self.create_def(closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, expr.span); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2052918747b39..159850098434e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -777,8 +777,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { visit::walk_fn_ret_ty(self, &declaration.output); // Resolve the function body, potentially inside the body of an async closure - if let IsAsync::Async(async_closure_id) = asyncness { - let rib_kind = ClosureRibKind(async_closure_id); + if let IsAsync::Async { closure_id, .. } = asyncness { + let rib_kind = ClosureRibKind(closure_id); self.ribs[ValueNS].push(Rib::new(rib_kind)); self.label_ribs.push(Rib::new(rib_kind)); } @@ -3935,8 +3935,9 @@ impl<'a> Resolver<'a> { // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. ExprKind::Closure( - _, IsAsync::Async(inner_closure_id), _, ref fn_decl, ref body, _span) => - { + _, IsAsync::Async { closure_id: inner_closure_id, .. }, _, + ref fn_decl, ref body, _span, + ) => { let rib_kind = ClosureRibKind(expr.id); self.ribs[ValueNS].push(Rib::new(rib_kind)); self.label_ribs.push(Rib::new(rib_kind)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ca07ac7988dfe..d38af6a608866 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1722,13 +1722,16 @@ pub enum Unsafety { #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum IsAsync { - Async(NodeId), + Async { + closure_id: NodeId, + return_impl_trait_id: NodeId, + }, NotAsync, } impl IsAsync { pub fn is_async(self) -> bool { - if let IsAsync::Async(_) = self { + if let IsAsync::Async { .. } = self { true } else { false diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c813ec1977b88..2a21e4c017112 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1726,7 +1726,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "labels on blocks are unstable"); } } - ast::ExprKind::Closure(_, ast::IsAsync::Async(_), ..) => { + ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => { gate_feature_post!(&self, async_await, e.span, "async closures are unstable"); } ast::ExprKind::Async(..) => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1035be3a15979..d9d3febc4fe4d 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -100,6 +100,10 @@ pub trait Folder : Sized { noop_fold_fn_decl(d, self) } + fn fold_asyncness(&mut self, a: IsAsync) -> IsAsync { + noop_fold_asyncness(a, self) + } + fn fold_block(&mut self, b: P) -> P { noop_fold_block(b, self) } @@ -669,6 +673,16 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) } } +pub fn noop_fold_asyncness(asyncness: IsAsync, fld: &mut T) -> IsAsync { + match asyncness { + IsAsync::Async { closure_id, return_impl_trait_id } => IsAsync::Async { + closure_id: fld.new_id(closure_id), + return_impl_trait_id: fld.new_id(return_impl_trait_id), + }, + IsAsync::NotAsync => IsAsync::NotAsync, + } +} + pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { decl.map(|FnDecl {inputs, output, variadic}| FnDecl { inputs: inputs.move_map(|x| fld.fold_arg(x)), @@ -996,10 +1010,7 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) } pub fn noop_fold_fn_header(mut header: FnHeader, folder: &mut T) -> FnHeader { - header.asyncness = match header.asyncness { - IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)), - IsAsync::NotAsync => IsAsync::NotAsync, - }; + header.asyncness = folder.fold_asyncness(header.asyncness); header } @@ -1249,12 +1260,8 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu arms.move_map(|x| folder.fold_arm(x))) } ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => { - let asyncness = match asyncness { - IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)), - IsAsync::NotAsync => IsAsync::NotAsync, - }; ExprKind::Closure(capture_clause, - asyncness, + folder.fold_asyncness(asyncness), movability, folder.fold_fn_decl(decl), folder.fold_expr(body), @@ -1265,7 +1272,11 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu opt_label.map(|label| folder.fold_label(label))) } ExprKind::Async(capture_clause, node_id, body) => { - ExprKind::Async(capture_clause, folder.new_id(node_id), folder.fold_block(body)) + ExprKind::Async( + capture_clause, + folder.new_id(node_id), + folder.fold_block(body), + ) } ExprKind::Assign(el, er) => { ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8690918c80525..4c86a64b0997b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1299,7 +1299,10 @@ impl<'a> Parser<'a> { /// Parse asyncness: `async` or nothing fn parse_asyncness(&mut self) -> IsAsync { if self.eat_keyword(keywords::Async) { - IsAsync::Async(ast::DUMMY_NODE_ID) + IsAsync::Async { + closure_id: ast::DUMMY_NODE_ID, + return_impl_trait_id: ast::DUMMY_NODE_ID, + } } else { IsAsync::NotAsync } @@ -3279,10 +3282,8 @@ impl<'a> Parser<'a> { } else { Movability::Movable }; - let asyncness = if self.span.edition() >= Edition::Edition2018 - && self.eat_keyword(keywords::Async) - { - IsAsync::Async(ast::DUMMY_NODE_ID) + let asyncness = if self.span.edition() >= Edition::Edition2018 { + self.parse_asyncness() } else { IsAsync::NotAsync }; @@ -6798,7 +6799,10 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, - IsAsync::Async(ast::DUMMY_NODE_ID), + IsAsync::Async { + closure_id: ast::DUMMY_NODE_ID, + return_impl_trait_id: ast::DUMMY_NODE_ID, + }, respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; From 62a561079133ae51f65409a3a4276d2fcfae8eb7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 11:56:47 +0200 Subject: [PATCH 08/18] Don't generate `DefId`s for impl trait in trait methods --- src/librustc/hir/lowering.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 004121147d904..cca5983e62b00 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3142,7 +3142,7 @@ impl<'a> LoweringContext<'a> { self.lower_impl_trait_ids(decl, &mut ids); ids }, - ItemKind::Impl(.., ref items) => { + ItemKind::Impl(.., None, _, ref items) => { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { From d5efa9636b6786dfe9d4a2d12c5895ea1dc5b8e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 11:57:03 +0200 Subject: [PATCH 09/18] Update tests --- src/test/compile-fail/private-type-in-interface.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs index 1842790a1405f..4235b4be27158 100644 --- a/src/test/compile-fail/private-type-in-interface.rs +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -35,6 +35,8 @@ type A = ::X; //~ ERROR type `m::Priv` is private trait Tr2 {} impl Tr2 for u8 {} fn g() -> impl Tr2 { 0 } //~ ERROR type `m::Priv` is private +//~^ ERROR type `m::Priv` is private fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private +//~^ ERROR type `ext::Priv` is private fn main() {} From 37cc714aa708b665411534742b221c8e0ccd0e4b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 14:39:37 +0200 Subject: [PATCH 10/18] Don't use `println` in the compiler --- src/librustc/hir/map/collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index f16bf1d774455..5c09a263ad128 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -232,7 +232,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { }; if hir_id == ::hir::DUMMY_HIR_ID { - println!("Maybe you forgot to lower the node id {:?}?", id); + debug!("Maybe you forgot to lower the node id {:?}?", id); } bug!("inconsistent DepNode for `{}`: \ From 0e775a3b865605dfa761995b8f3a8fb248971836 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 14:40:05 +0200 Subject: [PATCH 11/18] Don't visit the `impl Trait` item twice --- src/librustc/hir/intravisit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2a351d99841ff..f2d1678d33692 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -607,9 +607,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } visitor.visit_lifetime(lifetime); } - TyImplTraitExistential(item_id, def_id, ref lifetimes) => { + TyImplTraitExistential(_, def_id, ref lifetimes) => { visitor.visit_def_mention(Def::Existential(def_id)); - visitor.visit_nested_item(item_id); walk_list!(visitor, visit_lifetime, lifetimes); } TyTypeof(ref expression) => { From eb9043bc6739085bbe2fcd6d9d2c3f9346df22c8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 26 Jun 2018 16:35:52 +0200 Subject: [PATCH 12/18] Fix rebase fallout --- src/librustc/hir/lowering.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index cca5983e62b00..8e49ed2371459 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3598,7 +3598,7 @@ impl<'a> LoweringContext<'a> { ExprKind::Closure( capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span ) => { - if let IsAsync::Async { async_closure_node_id, .. } = asyncness { + if let IsAsync::Async { closure_id, .. } = asyncness { let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FunctionRetTy::Default(fn_decl_span), From a1f6a613f5236404f52bab95d20f2fb5a76132cb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 11:24:16 +0200 Subject: [PATCH 13/18] Undo if let -> match conversion --- src/librustc/hir/lowering.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8e49ed2371459..50fd8e0158055 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1352,9 +1352,8 @@ impl<'a> LoweringContext<'a> { } fn visit_ty(&mut self, t: &'v hir::Ty) { - match t.node { // Don't collect elided lifetimes used inside of `fn()` syntax - hir::Ty_::TyBareFn(_) => { + if let hir::Ty_::TyBareFn(_) = t.node { let old_collect_elided_lifetimes = self.collect_elided_lifetimes; self.collect_elided_lifetimes = false; @@ -1365,8 +1364,8 @@ impl<'a> LoweringContext<'a> { self.currently_bound_lifetimes.truncate(old_len); self.collect_elided_lifetimes = old_collect_elided_lifetimes; - }, - _ => hir::intravisit::walk_ty(self, t), + } else { + hir::intravisit::walk_ty(self, t) } } From a85b27915fe8d7b077535cd3fd8a7e1bafb1469d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 11:24:50 +0200 Subject: [PATCH 14/18] Document the `make_ret_async` argument's `NodeId` --- src/librustc/hir/lowering.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 50fd8e0158055..bf3b377b52dd0 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1870,7 +1870,8 @@ impl<'a> LoweringContext<'a> { // This guards against trait declarations and implementations where impl Trait is // disallowed. // make_ret_async: if `Some`, converts `-> T` into `-> impl Future` in the - // return type. This is used for `async fn` declarations. + // return type. This is used for `async fn` declarations. The `NodeId` is the id of the + // return type impl Trait item. fn lower_fn_decl( &mut self, decl: &FnDecl, From 5bd9eaa1ad20c3a84b162a825350f7b4c532e7ae Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 11:25:22 +0200 Subject: [PATCH 15/18] Add a convenience method for getting the impl Trait `NodeId` of an `IsAysnc` --- src/librustc/hir/lowering.rs | 40 ++++++++++++++---------------------- src/libsyntax/ast.rs | 7 +++++++ 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index bf3b377b52dd0..09911292ff533 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1352,18 +1352,18 @@ impl<'a> LoweringContext<'a> { } fn visit_ty(&mut self, t: &'v hir::Ty) { - // Don't collect elided lifetimes used inside of `fn()` syntax + // Don't collect elided lifetimes used inside of `fn()` syntax if let hir::Ty_::TyBareFn(_) = t.node { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - hir::intravisit::walk_ty(self, t); - self.currently_bound_lifetimes.truncate(old_len); + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + hir::intravisit::walk_ty(self, t); + self.currently_bound_lifetimes.truncate(old_len); - self.collect_elided_lifetimes = old_collect_elided_lifetimes; + self.collect_elided_lifetimes = old_collect_elided_lifetimes; } else { hir::intravisit::walk_ty(self, t) } @@ -2579,17 +2579,12 @@ impl<'a> LoweringContext<'a> { } }); - let asyncness = match header.asyncness { - IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), - IsAsync::NotAsync => None, - }; - let (generics, fn_decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, |this| this.lower_fn_decl( - decl, Some(fn_def_id), true, asyncness) + decl, Some(fn_def_id), true, header.asyncness.opt_return_id()) ); hir::ItemFn( @@ -3016,11 +3011,6 @@ impl<'a> LoweringContext<'a> { }); let impl_trait_return_allow = !self.is_in_trait_impl; - let asyncness = match sig.header.asyncness { - IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), - IsAsync::NotAsync => None, - }; - self.add_in_band_defs( &i.generics, impl_item_def_id, @@ -3031,7 +3021,7 @@ impl<'a> LoweringContext<'a> { sig, impl_item_def_id, impl_trait_return_allow, - asyncness, + sig.header.asyncness.opt_return_id(), ), body_id, ) @@ -3136,8 +3126,8 @@ impl<'a> LoweringContext<'a> { ItemKind::MacroDef(..) => SmallVector::new(), ItemKind::Fn(ref decl, ref header, ..) => { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); - if let IsAsync::Async { return_impl_trait_id, .. } = header.asyncness { - ids.push(hir::ItemId { id: return_impl_trait_id }); + if let Some(id) = header.asyncness.opt_return_id() { + ids.push(hir::ItemId { id }); } self.lower_impl_trait_ids(decl, &mut ids); ids @@ -3146,8 +3136,8 @@ impl<'a> LoweringContext<'a> { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { - if let IsAsync::Async { return_impl_trait_id, .. } = sig.header.asyncness { - ids.push(hir::ItemId { id: return_impl_trait_id }); + if let Some(id) = sig.header.asyncness.opt_return_id() { + ids.push(hir::ItemId { id }); } self.lower_impl_trait_ids(&sig.decl, &mut ids); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d38af6a608866..d767265ead9d4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1737,6 +1737,13 @@ impl IsAsync { false } } + /// In case this is an `Async` return the `NodeId` for the generated impl Trait item + pub fn opt_return_id(self) -> Option { + match self { + IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id), + IsAsync::NotAsync => None, + } + } } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] From 98a48fdae61bfbc59e10a3aba317fb5b23ed11bf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 11:37:52 +0200 Subject: [PATCH 16/18] Deduplicate async's impl Trait id lowering --- src/librustc/hir/lowering.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 09911292ff533..792f67b5ef5a0 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3081,8 +3081,12 @@ impl<'a> LoweringContext<'a> { fn lower_impl_trait_ids( &mut self, decl: &FnDecl, + header: &FnHeader, ids: &mut SmallVector, ) { + if let Some(id) = header.asyncness.opt_return_id() { + ids.push(hir::ItemId { id }); + } struct IdVisitor<'a> { ids: &'a mut SmallVector } impl<'a, 'b> Visitor<'a> for IdVisitor<'b> { fn visit_ty(&mut self, ty: &'a Ty) { @@ -3126,20 +3130,14 @@ impl<'a> LoweringContext<'a> { ItemKind::MacroDef(..) => SmallVector::new(), ItemKind::Fn(ref decl, ref header, ..) => { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); - if let Some(id) = header.asyncness.opt_return_id() { - ids.push(hir::ItemId { id }); - } - self.lower_impl_trait_ids(decl, &mut ids); + self.lower_impl_trait_ids(decl, header, &mut ids); ids }, ItemKind::Impl(.., None, _, ref items) => { let mut ids = SmallVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { - if let Some(id) = sig.header.asyncness.opt_return_id() { - ids.push(hir::ItemId { id }); - } - self.lower_impl_trait_ids(&sig.decl, &mut ids); + self.lower_impl_trait_ids(&sig.decl, &sig.header, &mut ids); } } ids From f21a98d8a9b6343effc4743dbb95507778181937 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 11:41:21 +0200 Subject: [PATCH 17/18] Explain the lack of item recursion --- src/librustc/hir/intravisit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f2d1678d33692..e06563f90e008 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -608,6 +608,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_lifetime(lifetime); } TyImplTraitExistential(_, def_id, ref lifetimes) => { + // we are not recursing into the `existential` item, because it is already being visited + // as part of the surrounding module. The `NodeId` just exists so we don't have to look + // it up everywhere else in the compiler visitor.visit_def_mention(Def::Existential(def_id)); walk_list!(visitor, visit_lifetime, lifetimes); } From 99575b5cac73a71685a783262249d803001a06a8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Jun 2018 12:03:59 +0200 Subject: [PATCH 18/18] Update ui tests --- src/test/ui/impl-trait/auto-trait-leak.stderr | 48 ++----------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index acb1a0557be95..6681116f0f393 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,10 +1,4 @@ -error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` - --> $DIR/auto-trait-leak.rs:24:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires processing `cycle1`... +error[E0391]: cycle detected when processing `cycle1` --> $DIR/auto-trait-leak.rs:24:1 | LL | fn cycle1() -> impl Clone { @@ -12,7 +6,7 @@ LL | fn cycle1() -> impl Clone { | note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:33:16 + --> $DIR/auto-trait-leak.rs:31:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ @@ -22,45 +16,13 @@ note: ...which requires processing `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle - -error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` +note: ...which requires processing `cycle1::{{impl-Trait}}`... --> $DIR/auto-trait-leak.rs:24:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ - | -note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:24:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:33:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:33:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle - -error[E0277]: `std::rc::Rc` cannot be sent between threads safely - --> $DIR/auto-trait-leak.rs:27:5 - | -LL | send(cycle2().clone()); - | ^^^^ `std::rc::Rc` cannot be sent between threads safely - | - = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` - = note: required because it appears within the type `impl std::clone::Clone` -note: required by `send` - --> $DIR/auto-trait-leak.rs:16:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires processing `cycle1`, completing the cycle +note: cycle used when type-checking all item bodies error: aborting due to previous error