From cf915849f0f9467e67823a9d7eb1128828a9f334 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sun, 19 Aug 2018 03:40:50 +0100 Subject: [PATCH 1/5] Lower `impl Trait` types in locals. --- src/librustc/diagnostics.rs | 5 +- src/librustc/hir/def_id.rs | 1 - src/librustc/hir/lowering.rs | 301 +++++++++++------- src/librustc/hir/map/def_collector.rs | 6 +- src/librustc/infer/opaque_types/mod.rs | 6 +- src/librustc/ty/sty.rs | 8 +- .../nll/type_check/input_output.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_typeck/check/_match.rs | 12 +- src/librustc_typeck/check/coercion.rs | 4 +- src/librustc_typeck/check/mod.rs | 87 ++--- src/librustc_typeck/check/writeback.rs | 4 +- 12 files changed, 262 insertions(+), 176 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3318bbd8c870e..c38b3510a0cc3 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1739,7 +1739,7 @@ specified exit code, use `std::process::exit`. E0562: r##" Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function return types. +allowed as function and inherent impl return types or binding types. Erroneous code example: @@ -1754,7 +1754,8 @@ fn main() { } ``` -Make sure `impl Trait` only appears in return-type position. +Make sure `impl Trait` only appears in return-type position or as the type of a +binding. ``` fn count_to_n(n: usize) -> impl Iterator { diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index cd91b85689b30..bbad157091b97 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -131,7 +131,6 @@ pub struct DefIndex(u32); /// thanks to `NodeCollector::new`. pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); - impl fmt::Debug for DefIndex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index bd8770abb135c..275ca6e169450 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -139,6 +139,7 @@ pub struct LoweringContext<'a> { type_def_lifetime_params: DefIdMap, current_hir_id_owner: Vec<(DefIndex, u32)>, + current_impl_trait_owner: Vec, item_local_id_counters: NodeMap, node_id_to_hir_id: IndexVec, } @@ -175,15 +176,17 @@ enum ImplTraitContext<'a> { /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually /// equivalent to a fresh universal parameter like `fn foo(x: T)`. /// - /// Newly generated parameters should be inserted into the given `Vec` + /// Newly generated parameters should be inserted into the given `Vec`. Universal(&'a mut Vec), - /// Treat `impl Trait` as shorthand for a new universal existential parameter. + /// Treat `impl Trait` as shorthand for a new existential parameter. /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually - /// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`. + /// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`. /// - /// We store a DefId here so we can look up necessary information later - Existential(DefId), + /// We optionally store a `DefId` for the parent item here so we can look up necessary + /// information later. It is `None` when no information about the context should be stored, + /// e.g. for consts and statics. + Existential(Option), /// `impl Trait` is not accepted in this position. Disallowed, @@ -230,6 +233,7 @@ pub fn lower_crate( anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, type_def_lifetime_params: DefIdMap(), current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], + current_impl_trait_owner: vec![], item_local_id_counters: NodeMap(), node_id_to_hir_id: IndexVec::new(), is_generator: false, @@ -305,6 +309,35 @@ enum AnonymousLifetimeMode { PassThrough, } +struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut OneVector } + +impl<'a, 'b> Visitor<'a> for ImplTraitTypeIdVisitor<'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.args { + if let GenericArgs::Parenthesized(_) = **p { + return; + } + } + visit::walk_path_segment(self, path_span, path_segment) + } +} + impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { /// Full-crate AST visitor that inserts into a fresh @@ -359,6 +392,17 @@ impl<'a> LoweringContext<'a> { } impl<'lcx, 'interner> ItemLowerer<'lcx, 'interner> { + fn with_impl_trait_owner(&mut self, def_id: DefId, f: F) -> T + where + F: FnOnce(&mut Self) -> T, + { + self.lctx.current_impl_trait_owner.push(def_id); + let ret = f(self); + self.lctx.current_impl_trait_owner.pop(); + + ret + } + fn with_trait_impl_ref(&mut self, trait_impl_ref: &Option, f: F) where F: FnOnce(&mut Self), @@ -396,7 +440,12 @@ impl<'a> LoweringContext<'a> { self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node { + if let ItemKind::Fn(..) = item.node { + let fn_def_id = this.lctx.resolver.definitions().local_def_id(item.id); + this.with_impl_trait_owner(fn_def_id, |this| { + visit::walk_item(this, item) + }); + } else if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.node { this.with_trait_impl_ref(opt_trait_ref, |this| { visit::walk_item(this, item) }); @@ -524,6 +573,17 @@ impl<'a> LoweringContext<'a> { ret } + fn with_impl_trait_owner(&mut self, def_id: DefId, f: F) -> T + where + F: FnOnce(&mut LoweringContext) -> T, + { + self.current_impl_trait_owner.push(def_id); + let ret = f(self); + self.current_impl_trait_owner.pop(); + + ret + } + /// This method allocates a new HirId for the given NodeId and stores it in /// the LoweringContext's NodeId => HirId map. /// Take care not to call this method if the resulting HirId is then not @@ -955,13 +1015,13 @@ impl<'a> LoweringContext<'a> { let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); - let result = f(self); + let ret = f(self); self.catch_scopes = catch_scopes; self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; - result + ret } fn def_key(&mut self, id: DefId) -> DefKey { @@ -1229,7 +1289,7 @@ impl<'a> LoweringContext<'a> { t.span, E0562, "`impl Trait` not allowed outside of function \ - and inherent method return types" + and inherent method return types or bindings" ); hir::TyKind::Err } @@ -1250,7 +1310,7 @@ impl<'a> LoweringContext<'a> { fn lower_existential_impl_trait( &mut self, span: Span, - fn_def_id: DefId, + fn_def_id: Option, exist_ty_node_id: NodeId, lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::GenericBounds, ) -> hir::TyKind { @@ -1270,7 +1330,6 @@ impl<'a> LoweringContext<'a> { .opt_def_index(exist_ty_node_id) .unwrap(); - self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait"); let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds); @@ -1292,7 +1351,7 @@ impl<'a> LoweringContext<'a> { span, }, bounds: hir_bounds, - impl_trait_fn: Some(fn_def_id), + impl_trait_fn: fn_def_id, }); let exist_ty_id = lctx.lower_node_id(exist_ty_node_id); // Generate an `existential type Foo: Trait;` declaration @@ -1865,20 +1924,34 @@ impl<'a> LoweringContext<'a> { ) } - fn lower_local(&mut self, l: &Local) -> P { + fn lower_local(&mut self, l: &Local) -> (P, OneVector) { let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id); - P(hir::Local { + let mut ids = OneVector::::new(); + if self.sess.features_untracked().impl_trait_in_bindings { + if let Some(ref ty) = l.ty { + let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; + visitor.visit_ty(ty); + } + } + let impl_trait_owner_id = self.current_impl_trait_owner.last().map(|id| *id); + (P(hir::Local { id: node_id, hir_id, ty: l.ty .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed)), + .map(|t| self.lower_ty(t, + if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::Existential(impl_trait_owner_id) + } else { + ImplTraitContext::Disallowed + } + )), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), span: l.span, attrs: l.attrs.clone(), source: hir::LocalSource::Normal, - }) + }), ids) } fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability { @@ -1948,7 +2021,7 @@ impl<'a> LoweringContext<'a> { match decl.output { FunctionRetTy::Ty(ref ty) => match in_band_ty_params { Some((def_id, _)) if impl_trait_return_allow => { - hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id))) + hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(Some(def_id)))) } _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), }, @@ -2131,10 +2204,10 @@ impl<'a> LoweringContext<'a> { }; let impl_trait_ty = self.lower_existential_impl_trait( - span, fn_def_id, return_impl_trait_id, |this| { + span, Some(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)), + this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))), FunctionRetTy::Default(span) => { let LoweredNodeId { node_id, hir_id } = this.next_id(); P(hir::Ty { @@ -2640,28 +2713,33 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); + self.with_impl_trait_owner(fn_def_id, |this| { + this.with_new_scopes(|this| { + // Note: we don't need to change the return type from `T` to + // `impl Future` here because lower_body + // only cares about the input argument patterns in the function + // declaration (decl), not the return types. + let body_id = this.lower_async_body(decl, header.asyncness, body); + + let (generics, fn_decl) = this.add_in_band_defs( + generics, + fn_def_id, + AnonymousLifetimeMode::PassThrough, + |this, idty| this.lower_fn_decl( + decl, + Some((fn_def_id, idty)), + true, + header.asyncness.opt_return_id() + ), + ); - self.with_new_scopes(|this| { - // Note: we don't need to change the return type from `T` to - // `impl Future` here because lower_body - // only cares about the input argument patterns in the function - // declaration (decl), not the return types. - let body_id = this.lower_async_body(decl, header.asyncness, body); - - let (generics, fn_decl) = this.add_in_band_defs( - generics, - fn_def_id, - AnonymousLifetimeMode::PassThrough, - |this, idty| this.lower_fn_decl( - decl, Some((fn_def_id, idty)), true, header.asyncness.opt_return_id()), - ); - - hir::ItemKind::Fn( - fn_decl, - this.lower_fn_header(header), - generics, - body_id, - ) + hir::ItemKind::Fn( + fn_decl, + this.lower_fn_header(header), + generics, + body_id, + ) + }) }) } ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), @@ -2980,31 +3058,33 @@ impl<'a> LoweringContext<'a> { ), ), TraitItemKind::Method(ref sig, None) => { - let names = self.lower_fn_args_to_names(&sig.decl); - let (generics, sig) = self.lower_method_sig( - &i.generics, - sig, - trait_item_def_id, - false, - None, - ); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) + self.with_impl_trait_owner(trait_item_def_id, |this| { + let names = this.lower_fn_args_to_names(&sig.decl); + let (generics, sig) = this.lower_method_sig( + &i.generics, + sig, + trait_item_def_id, + false, + None, + ); + (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) + }) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body_id = self.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) - }); - - let (generics, sig) = self.lower_method_sig( - &i.generics, - sig, - trait_item_def_id, - false, - None, - ); - - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) + self.with_impl_trait_owner(trait_item_def_id, |this| { + let body_id = this.lower_body(Some(&sig.decl), |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); + let (generics, sig) = this.lower_method_sig( + &i.generics, + sig, + trait_item_def_id, + false, + None, + ); + (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) + }) } TraitItemKind::Type(ref bounds, ref default) => ( self.lower_generics(&i.generics, ImplTraitContext::Disallowed), @@ -3070,16 +3150,18 @@ impl<'a> LoweringContext<'a> { ) } ImplItemKind::Method(ref sig, ref body) => { - let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness, body); - let impl_trait_return_allow = !self.is_in_trait_impl; - let (generics, sig) = self.lower_method_sig( - &i.generics, - sig, - impl_item_def_id, - impl_trait_return_allow, - sig.header.asyncness.opt_return_id(), - ); - (generics, hir::ImplItemKind::Method(sig, body_id)) + self.with_impl_trait_owner(impl_item_def_id, |this| { + let body_id = this.lower_async_body(&sig.decl, sig.header.asyncness, body); + let impl_trait_return_allow = !this.is_in_trait_impl; + let (generics, sig) = this.lower_method_sig( + &i.generics, + sig, + impl_item_def_id, + impl_trait_return_allow, + sig.header.asyncness.opt_return_id(), + ); + (generics, hir::ImplItemKind::Method(sig, body_id)) + }) } ImplItemKind::Type(ref ty) => ( self.lower_generics(&i.generics, ImplTraitContext::Disallowed), @@ -3137,8 +3219,8 @@ impl<'a> LoweringContext<'a> { } } - /// Lowers `impl Trait` items and appends them to the list - fn lower_impl_trait_ids( + /// Lowers `impl Trait` items for a function and appends them to the list + fn lower_fn_impl_trait_ids( &mut self, decl: &FnDecl, header: &FnHeader, @@ -3147,33 +3229,7 @@ impl<'a> LoweringContext<'a> { if let Some(id) = header.asyncness.opt_return_id() { ids.push(hir::ItemId { id }); } - struct IdVisitor<'a> { ids: &'a mut OneVector } - 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.args { - if let GenericArgs::Parenthesized(_) = **p { - return; - } - } - visit::walk_path_segment(self, path_span, path_segment) - } - } - let mut visitor = IdVisitor { ids }; + let mut visitor = ImplTraitTypeIdVisitor { ids }; match decl.output { FunctionRetTy::Default(_) => {}, FunctionRetTy::Ty(ref ty) => visitor.visit_ty(ty), @@ -3190,14 +3246,14 @@ impl<'a> LoweringContext<'a> { ItemKind::MacroDef(..) => OneVector::new(), ItemKind::Fn(ref decl, ref header, ..) => { let mut ids = smallvec![hir::ItemId { id: i.id }]; - self.lower_impl_trait_ids(decl, header, &mut ids); + self.lower_fn_impl_trait_ids(decl, header, &mut ids); ids }, ItemKind::Impl(.., None, _, ref items) => { let mut ids = smallvec![hir::ItemId { id: i.id }]; for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { - self.lower_impl_trait_ids(&sig.decl, &sig.header, &mut ids); + self.lower_fn_impl_trait_ids(&sig.decl, &sig.header, &mut ids); } } ids @@ -4312,15 +4368,32 @@ impl<'a> LoweringContext<'a> { fn lower_stmt(&mut self, s: &Stmt) -> OneVector { smallvec![match s.node { - StmtKind::Local(ref l) => Spanned { - node: hir::StmtKind::Decl( - P(Spanned { - node: hir::DeclKind::Local(self.lower_local(l)), + StmtKind::Local(ref l) => { + let (l, item_ids) = self.lower_local(l); + let mut ids: OneVector = item_ids + .into_iter() + .map(|item_id| Spanned { + node: hir::StmtKind::Decl( + P(Spanned { + node: hir::DeclKind::Item(item_id), + span: s.span, + }), + self.next_id().node_id, + ), span: s.span, - }), - self.lower_node_id(s.id).node_id, - ), - span: s.span, + }) + .collect(); + ids.push(Spanned { + node: hir::StmtKind::Decl( + P(Spanned { + node: hir::DeclKind::Local(l), + span: s.span, + }), + self.lower_node_id(s.id).node_id, + ), + span: s.span, + }); + return ids; }, StmtKind::Item(ref it) => { // Can only use the ID once. @@ -4334,8 +4407,8 @@ impl<'a> LoweringContext<'a> { span: s.span, }), id.take() - .map(|id| self.lower_node_id(id).node_id) - .unwrap_or_else(|| self.next_id().node_id), + .map(|id| self.lower_node_id(id).node_id) + .unwrap_or_else(|| self.next_id().node_id), ), span: s.span, }) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 57b3b43a338bb..26cf8f5d2ae5c 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -102,9 +102,9 @@ impl<'a> DefCollector<'a> { visit::walk_fn_decl(this, decl); let closure_def = this.create_def(closure_id, - DefPathData::ClosureExpr, - REGULAR_SPACE, - span); + DefPathData::ClosureExpr, + REGULAR_SPACE, + span); this.with_parent(closure_def, |this| { visit::walk_block(this, body); }) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index c6f910c4ad7a4..74ea393d64ad7 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -736,7 +736,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { debug!( "instantiate_opaque_types_in_map: \ - encountered opaque outside it's definition scope \ + encountered opaque outside its definition scope \ def_id={:?}", def_id, ); @@ -808,8 +808,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { for predicate in bounds.predicates { // Change the predicate to refer to the type variable, - // which will be the concrete type, instead of the Opaque. - // This also instantiates nested `impl Trait`. + // which will be the concrete type instead of the opaque type. + // This also instantiates nested instances of `impl Trait`. let predicate = self.instantiate_opaque_types_in_map(&predicate); let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8fb5ed66a82ef..8e4819b68a95f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -79,8 +79,8 @@ impl BoundRegion { } } -/// NB: If you change this, you'll probably want to change the corresponding -/// AST structure in libsyntax/ast.rs as well. +/// N.B., If you change this, you'll probably want to change the corresponding +/// AST structure in `libsyntax/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum TyKind<'tcx> { /// The primitive boolean type. Written as `bool`. @@ -158,7 +158,7 @@ pub enum TyKind<'tcx> { Projection(ProjectionTy<'tcx>), /// Opaque (`impl Trait`) type found in a return type. - /// The DefId comes either from + /// The `DefId` comes either from /// * the `impl Trait` ast::Ty node, /// * or the `existential type` declaration /// The substitutions are for the generics of the function in question. @@ -168,7 +168,7 @@ pub enum TyKind<'tcx> { /// A type parameter; for example, `T` in `fn f(x: T) {} Param(ParamTy), - /// A type variable used during type-checking. + /// A type variable used during type checking. Infer(InferTy), /// A placeholder for a type which could not be computed; this is diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index 6c7e2e9b72e30..d3b215fa07047 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -14,7 +14,7 @@ //! are supplied to us before normalization and may contain existential //! `impl Trait` instances. In contrast, the input/output types found in //! the MIR (specifically, in the special local variables for the -//! `RETURN_PLACE` the MIR arguments) are always fully normalize (and +//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). use borrow_check::nll::renumber; diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a20d7cc561979..250db4d15e675 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -98,7 +98,7 @@ mod relate_tys; /// to outlive; should represent the fn body /// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments; /// the types of the input parameters found in the MIR itself will be equated with these -/// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type; +/// - `output_ty` -- fully liberated, but **not** normalized, expected return type; /// the type for the RETURN_PLACE will be equated with this /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness /// constraints for the regions in the types of variables diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 0d2bc575401ef..ac754f9af58fc 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -235,7 +235,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .pat_binding_modes_mut() .insert(pat.hir_id, bm); debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); - let typ = self.local_ty(pat.span, pat.id); + let local_ty = self.local_ty(pat.span, pat.id).decl_ty; match bm { ty::BindByReference(mutbl) => { // if the binding is like @@ -249,28 +249,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for // an explanation. - self.demand_eqtype(pat.span, region_ty, typ); + self.demand_eqtype(pat.span, region_ty, local_ty); } // otherwise the type of x is the expected type T ty::BindByValue(_) => { // As above, `T <: typeof(x)` is required but we // use equality, see (*) below. - self.demand_eqtype(pat.span, expected, typ); + self.demand_eqtype(pat.span, expected, local_ty); } } // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be if var_id != pat.id { - let vt = self.local_ty(pat.span, var_id); - self.demand_eqtype(pat.span, vt, typ); + let vt = self.local_ty(pat.span, var_id).decl_ty; + self.demand_eqtype(pat.span, vt, local_ty); } if let Some(ref p) = *sub { self.check_pat_walk(&p, expected, def_bm, true); } - typ + local_ty } PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 9604eb3420fb3..716dfce32fdcb 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1039,8 +1039,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> } /// Indicates that the value generated by `expression`, which is - /// of type `expression_ty`, is one of the possibility that we - /// could coerce from. This will record `expression` and later + /// of type `expression_ty`, is one of the possibilities that we + /// could coerce from. This will record `expression`, and later /// calls to `coerce` may come back and add adjustments and things /// if necessary. pub fn coerce<'a>(&mut self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0dc7bc75c3d40..d68899e216ce1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -154,6 +154,13 @@ mod generator_interior; mod intrinsic; mod op; +/// The type of a local binding, including the revealed type for anon types. +#[derive(Copy, Clone)] +pub struct LocalTy<'tcx> { + decl_ty: Ty<'tcx>, + revealed_ty: Ty<'tcx> +} + /// A wrapper for InferCtxt's `in_progress_tables` field. #[derive(Copy, Clone)] struct MaybeInProgressTables<'a, 'tcx: 'a> { @@ -180,7 +187,6 @@ impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { } } - /// closures defined within the function. For example: /// /// fn foo() { @@ -195,7 +201,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tables: MaybeInProgressTables<'a, 'tcx>, - locals: RefCell>>, + locals: RefCell>>, fulfillment_cx: RefCell>>, @@ -864,7 +870,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); // Gather locals in statics (because of block expressions). - GatherLocalsVisitor { fcx: &fcx }.visit_body(body); + GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body); fcx.check_expr_coercable_to_type(&body.value, expected_type); @@ -914,22 +920,26 @@ fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) { } struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx> + fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + parent_id: ast::NodeId, } impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { - fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { + fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { match ty_opt { None => { // infer the variable's type let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); - self.fcx.locals.borrow_mut().insert(nid, var_ty); + self.fcx.locals.borrow_mut().insert(nid, LocalTy { + decl_ty: var_ty, + revealed_ty: var_ty + }); var_ty } Some(typ) => { // take type that the user specified self.fcx.locals.borrow_mut().insert(nid, typ); - typ + typ.revealed_ty } } } @@ -942,24 +952,28 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'gcx hir::Local) { - let o_ty = match local.ty { + let local_ty = match local.ty { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); + debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1); - let c_ty = self.fcx.inh.infcx.canonicalize_response(&o_ty); - debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); + let revealed_ty = self.fcx.instantiate_opaque_types_from_value( + self.parent_id, + &o_ty); + + let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); - Some(o_ty) + Some(LocalTy { decl_ty: o_ty, revealed_ty }) }, None => None, }; - self.assign(local.span, local.id, o_ty); + self.assign(local.span, local.id, local_ty); debug!("Local variable {:?} is assigned type {}", local.pat, self.fcx.ty_to_string( - self.fcx.locals.borrow().get(&local.id).unwrap().clone())); + self.fcx.locals.borrow().get(&local.id).unwrap().clone().decl_ty)); intravisit::walk_local(self, local); } @@ -976,7 +990,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { debug!("Pattern binding {} is assigned to {} with type {:?}", ident, self.fcx.ty_to_string( - self.fcx.locals.borrow().get(&p.id).unwrap().clone()), + self.fcx.locals.borrow().get(&p.id).unwrap().clone().decl_ty), var_ty); } intravisit::walk_pat(self, p); @@ -1027,7 +1041,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let declared_ret_ty = fn_sig.output(); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - let revealed_ret_ty = fcx.instantiate_opaque_types_from_return_value(fn_id, &declared_ret_ty); + let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), @@ -1045,7 +1059,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.yield_ty = Some(yield_ty); } - GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); + GatherLocalsVisitor { fcx: &fcx, parent_id: fn_id, }.visit_body(body); // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { @@ -2040,7 +2054,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("{:?}", self_ptr) } - pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> { + pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> LocalTy<'tcx> { match self.locals.borrow().get(&nid) { Some(&t) => t, None => { @@ -2225,18 +2239,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { result } - /// Replace the opaque types from the return value of the - /// function with type variables and records the `OpaqueTypeMap` for - /// later use during writeback. See + /// Replace the opaque types from the given value with type variables, + /// and records the `OpaqueTypeMap` for later use during writeback. See /// `InferCtxt::instantiate_opaque_types` for more details. - fn instantiate_opaque_types_from_return_value>( + fn instantiate_opaque_types_from_value>( &self, fn_id: ast::NodeId, value: &T, ) -> T { let fn_def_id = self.tcx.hir.local_def_id(fn_id); debug!( - "instantiate_opaque_types_from_return_value(fn_def_id={:?}, value={:?})", + "instantiate_opaque_types_from_value(fn_def_id={:?}, value={:?})", fn_def_id, value ); @@ -2889,7 +2902,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); // We're processing function arguments so we definitely want to use // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes); + self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes); // 3. Relate the expected type and the formal one, // if the expected type was used for the coercion. @@ -3048,7 +3061,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_coerce(expr, ty, expected, AllowTwoPhase::No) } - fn check_expr_with_hint(&self, expr: &'gcx hir::Expr, + fn check_expr_with_hint(&self, + expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { self.check_expr_with_expectation(expr, ExpectHasType(expected)) } @@ -3197,7 +3211,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_expr_ty); } - // A generic function for checking the then and else in an if // or if-else. fn check_then_else(&self, @@ -3739,9 +3752,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// that there are actually multiple representations for `Error`, so avoid /// that when err needs to be handled differently. fn check_expr_with_expectation_and_needs(&self, - expr: &'gcx hir::Expr, - expected: Expectation<'tcx>, - needs: Needs) -> Ty<'tcx> { + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>, + needs: Needs) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); @@ -3827,8 +3840,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => Needs::None }; let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, - expected_inner, - needs); + expected_inner, + needs); if !oprnd_t.references_error() { oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); @@ -3858,8 +3871,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.write_method_call(expr.hir_id, method); } else { type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614, - "type `{}` cannot be dereferenced", - oprnd_t).emit(); + "type `{}` cannot be dereferenced", + oprnd_t).emit(); oprnd_t = tcx.types.err; } } @@ -3923,6 +3936,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::Path(ref qpath) => { let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span); + debug!("path_foo: {:?} {:?}", def, opt_ty); let ty = if def != Def::Err { self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0 } else { @@ -4083,7 +4097,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => { self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected) + expr.span, expected) } hir::ExprKind::While(ref cond, ref body, _) => { let ctxt = BreakableCtxt { @@ -4471,7 +4485,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // See #44848. let ref_bindings = local.pat.contains_explicit_ref_binding(); - let local_ty = self.local_ty(init.span, local.id); + let local_ty = self.local_ty(init.span, local.id).revealed_ty; if let Some(m) = ref_bindings { // Somewhat subtle: if we have a `ref` binding in the pattern, // we want to avoid introducing coercions for the RHS. This is @@ -4490,7 +4504,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_decl_local(&self, local: &'gcx hir::Local) { - let t = self.local_ty(local.span, local.id); + let t = self.local_ty(local.span, local.id).decl_ty; self.write_ty(local.hir_id, t); if let Some(ref init) = local.init { @@ -4827,7 +4841,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// A possible error is to forget to add a return type that is needed: /// /// ``` @@ -5069,7 +5082,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match def { Def::Local(nid) | Def::Upvar(nid, ..) => { - let ty = self.local_ty(span, nid); + let ty = self.local_ty(span, nid).decl_ty; let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(self.tcx.hir.node_to_hir_id(node_id), ty); return (ty, def); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0b2f92ac4bcb6..6595ce0facf69 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -75,7 +75,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// The Writerback context. This visitor walks the AST, checking the +// The Writeback context. This visitor walks the AST, checking the // fn-specific tables to find references to types or regions. It // resolves those regions to remove inference variables and writes the // final result back into the master tables in the tcx. Here and @@ -290,7 +290,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_local(&mut self, l: &'gcx hir::Local) { intravisit::walk_local(self, l); - let var_ty = self.fcx.local_ty(l.span, l.id); + let var_ty = self.fcx.local_ty(l.span, l.id).decl_ty; let var_ty = self.resolve(&var_ty, &l.span); self.write_ty_to_tables(l.hir_id, var_ty); } From 218189536d95c12d7abbe01af3725c84a628bc51 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 8 Sep 2018 07:52:03 +0100 Subject: [PATCH 2/5] Handle impl trait in MIR type checked for assignments. --- src/librustc/diagnostics.rs | 5 +- src/librustc/hir/lowering.rs | 57 +++++- src/librustc/ty/relate.rs | 2 +- .../nll/type_check/input_output.rs | 147 ++------------ .../borrow_check/nll/type_check/mod.rs | 159 ++++++++++++++- src/librustc_typeck/check/mod.rs | 186 ++++++++++-------- src/libsyntax/feature_gate.rs | 7 +- .../feature-gate-impl_trait_in_bindings.rs | 17 ++ ...feature-gate-impl_trait_in_bindings.stderr | 21 ++ ...fs.rs => feature-gate-self_in_typedefs.rs} | 0 ...r => feature-gate-self_in_typedefs.stderr} | 2 +- 11 files changed, 368 insertions(+), 235 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs create mode 100644 src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr rename src/test/ui/feature-gates/{feature-gate-self-in-typedefs.rs => feature-gate-self_in_typedefs.rs} (100%) rename src/test/ui/feature-gates/{feature-gate-self-in-typedefs.stderr => feature-gate-self_in_typedefs.stderr} (84%) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c38b3510a0cc3..84afdd53cf48c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1739,7 +1739,7 @@ specified exit code, use `std::process::exit`. E0562: r##" Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function and inherent impl return types or binding types. +allowed as function and inherent impl return types. Erroneous code example: @@ -1754,8 +1754,7 @@ fn main() { } ``` -Make sure `impl Trait` only appears in return-type position or as the type of a -binding. +Make sure `impl Trait` only appears in return-type position. ``` fn count_to_n(n: usize) -> impl Iterator { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 275ca6e169450..f25a17304f9ed 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1284,12 +1284,18 @@ impl<'a> LoweringContext<'a> { )) } ImplTraitContext::Disallowed => { + let allowed_in = if self.sess.features_untracked() + .impl_trait_in_bindings { + "bindings or function and inherent method return types" + } else { + "function and inherent method return types" + }; span_err!( self.sess, t.span, E0562, - "`impl Trait` not allowed outside of function \ - and inherent method return types or bindings" + "`impl Trait` not allowed outside of {}", + allowed_in, ); hir::TyKind::Err } @@ -2206,8 +2212,10 @@ impl<'a> LoweringContext<'a> { let impl_trait_ty = self.lower_existential_impl_trait( span, Some(fn_def_id), return_impl_trait_id, |this| { let output_ty = match output { - FunctionRetTy::Ty(ty) => - this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))), + FunctionRetTy::Ty(ty) => { + let impl_trait_owner_id = *this.current_impl_trait_owner.last().unwrap(); + this.lower_ty(ty, ImplTraitContext::Existential(Some(impl_trait_owner_id))) + } FunctionRetTy::Default(span) => { let LoweredNodeId { node_id, hir_id } = this.next_id(); P(hir::Ty { @@ -2702,14 +2710,31 @@ impl<'a> LoweringContext<'a> { ItemKind::Static(ref t, m, ref e) => { let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemKind::Static( - self.lower_ty(t, ImplTraitContext::Disallowed), + self.lower_ty( + t, + if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::Existential(None) + } else { + ImplTraitContext::Disallowed + } + ), self.lower_mutability(m), value, ) } ItemKind::Const(ref t, ref e) => { let value = self.lower_body(None, |this| this.lower_expr(e)); - hir::ItemKind::Const(self.lower_ty(t, ImplTraitContext::Disallowed), value) + hir::ItemKind::Const( + self.lower_ty( + t, + if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::Existential(None) + } else { + ImplTraitContext::Disallowed + } + ), + value + ) } ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); @@ -3258,6 +3283,22 @@ impl<'a> LoweringContext<'a> { } ids }, + ItemKind::Static(ref ty, ..) => { + let mut ids = smallvec![hir::ItemId { id: i.id }]; + if self.sess.features_untracked().impl_trait_in_bindings { + let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; + visitor.visit_ty(ty); + } + ids + }, + ItemKind::Const(ref ty, ..) => { + let mut ids = smallvec![hir::ItemId { id: i.id }]; + if self.sess.features_untracked().impl_trait_in_bindings { + let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; + visitor.visit_ty(ty); + } + ids + }, _ => smallvec![hir::ItemId { id: i.id }], } } @@ -3817,8 +3858,8 @@ impl<'a> LoweringContext<'a> { } ExprKind::Block(ref blk, opt_label) => { hir::ExprKind::Block(self.lower_block(blk, - opt_label.is_some()), - self.lower_label(opt_label)) + opt_label.is_some()), + self.lower_label(opt_label)) } ExprKind::Assign(ref el, ref er) => { hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er))) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8f84fb7e39101..98042e18d32d9 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -361,7 +361,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let tcx = relation.tcx(); let a_sty = &a.sty; let b_sty = &b.sty; - debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + debug!("super_relate_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); match (a_sty, b_sty) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index d3b215fa07047..acde4587d77dc 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -17,15 +17,8 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use borrow_check::nll::renumber; -use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; -use rustc::hir::def_id::DefId; -use rustc::infer::InferOk; use rustc::mir::*; -use rustc::traits::query::type_op::custom::CustomTypeOp; -use rustc::traits::{ObligationCause, PredicateObligations}; -use rustc::ty::subst::Subst; use rustc::ty::Ty; use rustc_data_structures::indexed_vec::Idx; @@ -37,16 +30,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { pub(super) fn equate_inputs_and_outputs( &mut self, mir: &Mir<'tcx>, - mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, - universal_region_relations: &UniversalRegionRelations<'tcx>, normalized_inputs_and_output: &[Ty<'tcx>], ) { - let tcx = self.infcx.tcx; - let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); - let infcx = self.infcx; // Equate expected input tys with those in the MIR. let argument_locals = (1..).map(Local::new); @@ -77,111 +65,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // Return types are a bit more complex. They may contain existential `impl Trait` // types. - let param_env = self.param_env; let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; let output_span = mir.local_decls[RETURN_PLACE].source_info.span; - let opaque_type_map = - self.fully_perform_op( - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - CustomTypeOp::new( - |infcx| { - let mut obligations = ObligationAccumulator::default(); - - let dummy_body_id = ObligationCause::dummy().body_id; - let (output_ty, opaque_type_map) = - obligations.add(infcx.instantiate_opaque_types( - mir_def_id, - dummy_body_id, - param_env, - &normalized_output_ty, - )); - debug!( - "equate_inputs_and_outputs: instantiated output_ty={:?}", - output_ty - ); - debug!( - "equate_inputs_and_outputs: opaque_type_map={:#?}", - opaque_type_map - ); - - debug!( - "equate_inputs_and_outputs: mir_output_ty={:?}", - mir_output_ty - ); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(output_ty, mir_output_ty)?, - ); - - for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let opaque_defn_ty = tcx.type_of(opaque_def_id); - let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); - let opaque_defn_ty = renumber::renumber_regions( - infcx, - &opaque_defn_ty, - ); - debug!( - "equate_inputs_and_outputs: concrete_ty={:?}", - opaque_decl.concrete_ty - ); - debug!("equate_inputs_and_outputs: opaque_defn_ty={:?}", - opaque_defn_ty); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, - ); - } - - debug!("equate_inputs_and_outputs: equated"); - - Ok(InferOk { - value: Some(opaque_type_map), - obligations: obligations.into_vec(), - }) - }, - || "input_output".to_string(), - ), - ).unwrap_or_else(|terr| { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - normalized_output_ty, - mir_output_ty, - terr - ); - None - }); - - // Finally, if we instantiated the opaque types successfully, we - // have to solve any bounds (e.g., `-> impl Iterator` needs to - // prove that `T: Iterator` where `T` is the type we - // instantiated it with). - if let Some(opaque_type_map) = opaque_type_map { - for (opaque_def_id, opaque_decl) in opaque_type_map { - self.fully_perform_op( - Locations::All(infcx.tcx.def_span(opaque_def_id)), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |_cx| { - infcx.constrain_opaque_type( - opaque_def_id, - &opaque_decl, - universal_region_relations - ); - Ok(InferOk { - value: (), - obligations: vec![], - }) - }, - || "opaque_type_map".to_string(), - ), - ).unwrap(); - } - } + if let Err(terr) = self.eq_opaque_type_and_type( + mir_output_ty, + normalized_output_ty, + Locations::All(output_span), + ConstraintCategory::BoringNoLocation, + ) { + span_mirbug!( + self, + Location::START, + "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", + normalized_output_ty, + mir_output_ty, + terr + ); + }; } fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { @@ -204,20 +104,3 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } - -#[derive(Debug, Default)] -struct ObligationAccumulator<'tcx> { - obligations: PredicateObligations<'tcx>, -} - -impl<'tcx> ObligationAccumulator<'tcx> { - fn add(&mut self, value: InferOk<'tcx, T>) -> T { - let InferOk { value, obligations } = value; - self.obligations.extend(obligations); - value - } - - fn into_vec(self) -> PredicateObligations<'tcx> { - self.obligations - } -} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 250db4d15e675..8d260e0970add 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -22,6 +22,7 @@ use borrow_check::nll::type_check::free_region_relations::{ }; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::ToRegionVid; +use borrow_check::nll::renumber; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; @@ -29,15 +30,18 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::region_constraints::GenericKind; -use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::*; +use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::traits::query::type_op; +use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; +use rustc::ty::subst::Subst; use std::fmt; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; @@ -155,12 +159,11 @@ pub(crate) fn type_check<'gcx, 'tcx>( ®ion_bound_pairs, Some(implicit_region_bound), Some(&mut borrowck_context), + Some(&universal_region_relations), |cx| { cx.equate_inputs_and_outputs( mir, - mir_def_id, universal_regions, - &universal_region_relations, &normalized_inputs_and_output, ); liveness::generate(cx, mir, elements, flow_inits, move_data); @@ -182,6 +185,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>( region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R, ) -> R where { let mut checker = TypeChecker::new( @@ -192,6 +196,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>( region_bound_pairs, implicit_region_bound, borrowck_context, + universal_region_relations, ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, mir); @@ -692,6 +697,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> { implicit_region_bound: Option>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -799,6 +805,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, ) -> Self { TypeChecker { infcx, @@ -810,6 +817,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: FxHashSet(), + universal_region_relations, } } @@ -883,6 +891,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) } + fn sub_types_or_anon( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + if let Err(terr) = self.sub_types(sub, sup, locations) { + if let TyKind::Opaque(..) = sup.sty { + return self.eq_opaque_type_and_type(sub, sup, locations, category); + } else { + return Err(terr); + } + } + Ok(()) + } + fn eq_types( &mut self, a: Ty<'tcx>, @@ -919,6 +944,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) } + fn eq_opaque_type_and_type( + &mut self, + revealed_ty: Ty<'tcx>, + anon_ty: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + let infcx = self.infcx; + let tcx = infcx.tcx; + let param_env = self.param_env; + let mir_def_id = self.mir_def_id; + let opaque_type_map = + self.fully_perform_op( + locations, + CustomTypeOp::new( + |infcx| { + let mut obligations = ObligationAccumulator::default(); + + let dummy_body_id = ObligationCause::dummy().body_id; + let (output_ty, opaque_type_map) = + obligations.add(infcx.instantiate_opaque_types( + mir_def_id, + dummy_body_id, + param_env, + &anon_ty, + )); + debug!( + "eq_opaque_type_and_type: \ + instantiated output_ty={:?} \ + opaque_type_map={:#?} \ + revealed_ty={:?}", + output_ty, + opaque_type_map, + revealed_ty + ); + obligations.add( + infcx + .at(&ObligationCause::dummy(), param_env) + .eq(output_ty, revealed_ty)?, + ); + + for (&opaque_def_id, opaque_decl) in &opaque_type_map { + let opaque_defn_ty = tcx.type_of(opaque_def_id); + let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); + let opaque_defn_ty = renumber::renumber_regions( + infcx, + &opaque_defn_ty, + ); + debug!( + "eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}", + opaque_decl.concrete_ty, + opaque_defn_ty + ); + obligations.add( + infcx + .at(&ObligationCause::dummy(), param_env) + .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, + ); + } + + debug!("eq_opaque_type_and_type: equated"); + + Ok(InferOk { + value: Some(opaque_type_map), + obligations: obligations.into_vec(), + }) + }, + || "input_output".to_string(), + ), + )?; + + let universal_region_relations = match self.universal_region_relations { + Some(rel) => rel, + None => return Ok(()), + }; + + // Finally, if we instantiated the anon types successfully, we + // have to solve any bounds (e.g., `-> impl Iterator` needs to + // prove that `T: Iterator` where `T` is the type we + // instantiated it with). + if let Some(opaque_type_map) = opaque_type_map { + for (opaque_def_id, opaque_decl) in opaque_type_map { + self.fully_perform_op( + locations, + category, + CustomTypeOp::new( + |_cx| { + infcx.constrain_opaque_type( + opaque_def_id, + &opaque_decl, + universal_region_relations + ); + Ok(InferOk { + value: (), + obligations: vec![], + }) + }, + || "opaque_type_map".to_string(), + ), + )?; + } + } + Ok(()) + } + fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx } @@ -942,7 +1072,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = self.sub_types( + if let Err(terr) = self.sub_types_or_anon( rv_ty, place_ty, location.to_locations(), @@ -1235,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); - if let Err(terr) = self.sub_types( + if let Err(terr) = self.sub_types_or_anon( sig.output(), dest_ty, locations, @@ -2104,6 +2234,7 @@ impl MirPass for TypeckMir { &[], None, None, + None, |_| (), ); @@ -2128,3 +2259,21 @@ impl NormalizeLocation for Location { Locations::Single(self) } } + +#[derive(Debug, Default)] +struct ObligationAccumulator<'tcx> { + obligations: PredicateObligations<'tcx>, +} + +impl<'tcx> ObligationAccumulator<'tcx> { + fn add(&mut self, value: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = value; + self.obligations.extend(obligations); + value + } + + fn into_vec(self) -> PredicateObligations<'tcx> { + self.obligations + } +} + diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d68899e216ce1..7265d82935b5e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -65,7 +65,7 @@ nodes within the function. The types of top-level items, which never contain unbound type variables, are stored directly into the `tcx` tables. -n.b.: A type variable is not the same thing as a type parameter. A +N.B.: A type variable is not the same thing as a type parameter. A type variable is rather an "instance" of a type parameter: that is, given a generic function `fn foo(t: T)`: while checking the function `foo`, the type `ty_param(0)` refers to the type `T`, which @@ -852,7 +852,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_abi(tcx, span, fn_sig.abi()); - // Compute the fty from point of view of inside fn. + // Compute the fty from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); let fn_sig = @@ -869,10 +869,20 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); + let revealed_ty = if tcx.features().impl_trait_in_bindings { + fcx.require_type_is_sized(expected_type, body.value.span, traits::SizedReturnType); + fcx.instantiate_opaque_types_from_value( + id, + &expected_type + ) + } else { + expected_type + }; + // Gather locals in statics (because of block expressions). GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body); - fcx.check_expr_coercable_to_type(&body.value, expected_type); + fcx.check_expr_coercable_to_type(&body.value, revealed_ty); fcx }; @@ -957,9 +967,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { let o_ty = self.fcx.to_ty(&ty); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1); - let revealed_ty = self.fcx.instantiate_opaque_types_from_value( - self.parent_id, - &o_ty); + let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { + self.fcx.instantiate_opaque_types_from_value( + self.parent_id, + &o_ty + ) + } else { + o_ty + }; let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); @@ -1288,90 +1303,96 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_packed(tcx, span, def_id); } -pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { - debug!("check_item_type(it.id={}, it.name={})", - it.id, - tcx.item_path_str(tcx.hir.local_def_id(it.id))); +pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { + debug!( + "check_item_type(it.id={}, it.name={})", + it.id, + tcx.item_path_str(tcx.hir.local_def_id(it.id)) + ); let _indenter = indenter(); match it.node { - // Consts can play a role in type-checking, so they are included here. - hir::ItemKind::Static(..) => { - let def_id = tcx.hir.local_def_id(it.id); - tcx.typeck_tables_of(def_id); - maybe_check_static_with_link_section(tcx, def_id, it.span); - } - hir::ItemKind::Const(..) => { - tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); - } - hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, - it.span, - &enum_definition.variants, - it.id); - } - hir::ItemKind::Fn(..) => {} // entirely within check_item_body - hir::ItemKind::Impl(.., ref impl_item_refs) => { - debug!("ItemKind::Impl {} with id {}", it.name, it.id); - let impl_def_id = tcx.hir.local_def_id(it.id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { - check_impl_items_against_trait(tcx, - it.span, - impl_def_id, - impl_trait_ref, - impl_item_refs); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); - } - } - hir::ItemKind::Trait(..) => { - let def_id = tcx.hir.local_def_id(it.id); - check_on_unimplemented(tcx, def_id, it); - } - hir::ItemKind::Struct(..) => { - check_struct(tcx, it.id, it.span); - } - hir::ItemKind::Union(..) => { - check_union(tcx, it.id, it.span); - } - hir::ItemKind::Existential(..) | - hir::ItemKind::Ty(..) => { - let def_id = tcx.hir.local_def_id(it.id); - let pty_ty = tcx.type_of(def_id); - let generics = tcx.generics_of(def_id); - check_bounds_are_used(tcx, &generics, pty_ty); - } - hir::ItemKind::ForeignMod(ref m) => { - check_abi(tcx, it.span, m.abi); - - if m.abi == Abi::RustIntrinsic { - for item in &m.items { - intrinsic::check_intrinsic_type(tcx, item); - } - } else if m.abi == Abi::PlatformIntrinsic { - for item in &m.items { - intrinsic::check_platform_intrinsic_type(tcx, item); + // Consts can play a role in type-checking, so they are included here. + hir::ItemKind::Static(..) => { + let def_id = tcx.hir.local_def_id(it.id); + tcx.typeck_tables_of(def_id); + maybe_check_static_with_link_section(tcx, def_id, it.span); + } + hir::ItemKind::Const(..) => { + tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); + } + hir::ItemKind::Enum(ref enum_definition, _) => { + check_enum(tcx, it.span, &enum_definition.variants, it.id); + } + hir::ItemKind::Fn(..) => {} // entirely within check_item_body + hir::ItemKind::Impl(.., ref impl_item_refs) => { + debug!("ItemKind::Impl {} with id {}", it.name, it.id); + let impl_def_id = tcx.hir.local_def_id(it.id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait( + tcx, + it.span, + impl_def_id, + impl_trait_ref, + impl_item_refs, + ); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(tcx, trait_def_id, it); } - } else { - for item in &m.items { - let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); - if generics.params.len() - generics.own_counts().lifetimes != 0 { - let mut err = struct_span_err!(tcx.sess, item.span, E0044, - "foreign items may not have type parameters"); - err.span_label(item.span, "can't have type parameters"); - // FIXME: once we start storing spans for type arguments, turn this into a - // suggestion. - err.help("use specialization instead of type parameters by replacing them \ - with concrete types like `u32`"); - err.emit(); + } + hir::ItemKind::Trait(..) => { + let def_id = tcx.hir.local_def_id(it.id); + check_on_unimplemented(tcx, def_id, it); + } + hir::ItemKind::Struct(..) => { + check_struct(tcx, it.id, it.span); + } + hir::ItemKind::Union(..) => { + check_union(tcx, it.id, it.span); + } + hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => { + let def_id = tcx.hir.local_def_id(it.id); + let pty_ty = tcx.type_of(def_id); + let generics = tcx.generics_of(def_id); + check_bounds_are_used(tcx, &generics, pty_ty); + } + hir::ItemKind::ForeignMod(ref m) => { + check_abi(tcx, it.span, m.abi); + + if m.abi == Abi::RustIntrinsic { + for item in &m.items { + intrinsic::check_intrinsic_type(tcx, item); + } + } else if m.abi == Abi::PlatformIntrinsic { + for item in &m.items { + intrinsic::check_platform_intrinsic_type(tcx, item); } + } else { + for item in &m.items { + let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); + if generics.params.len() - generics.own_counts().lifetimes != 0 { + let mut err = struct_span_err!( + tcx.sess, + item.span, + E0044, + "foreign items may not have type parameters" + ); + err.span_label(item.span, "can't have type parameters"); + // FIXME: once we start storing spans for type arguments, turn this into a + // suggestion. + err.help( + "use specialization instead of type parameters by replacing them \ + with concrete types like `u32`", + ); + err.emit(); + } - if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node { - require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span); + if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node { + require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span); + } } } } - } - _ => {/* nothing to do */ } + _ => { /* nothing to do */ } } } @@ -3936,7 +3957,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::Path(ref qpath) => { let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span); - debug!("path_foo: {:?} {:?}", def, opt_ty); let ty = if def != Def::Err { self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0 } else { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 65ffd96e7a0d2..eb40ea016303b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -494,7 +494,7 @@ declare_features! ( // Allows `Self` in type definitions (active, self_in_typedefs, "1.30.0", Some(49303), None), - // unsized rvalues at arguments and parameters + // Allows unsized rvalues at arguments and parameters (active, unsized_locals, "1.30.0", Some(48055), None), // #![test_runner] @@ -505,13 +505,16 @@ declare_features! ( (active, custom_inner_attributes, "1.30.0", Some(38356), None), // Self struct constructor (RFC 2302) - (active, self_struct_ctor, "1.31.0", Some(51994), None), + (active, self_struct_ctor, "1.30.0", Some(51994), None), // allow mixing of bind-by-move in patterns and references to // those identifiers in guards, *if* we are using MIR-borrowck // (aka NLL). Essentially this means you need to be on // edition:2018 or later. (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), + + // Allows `impl Trait` in bindings (`let`, `const`, `static`) + (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), ); declare_features! ( diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs new file mode 100644 index 0000000000000..9c76719e26cf2 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: impl Copy = 42; + +static BAR: impl Copy = 42; + +fn main() { + let foo = impl Copy = 42; +} diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr new file mode 100644 index 0000000000000..52c99a7b159e3 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr @@ -0,0 +1,21 @@ +error: expected expression, found keyword `impl` + --> $DIR/feature-gate-impl_trait_in_bindings.rs:16:15 + | +LL | let foo = impl Copy = 42; + | ^^^^ expected expression + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-impl_trait_in_bindings.rs:11:12 + | +LL | const FOO: impl Copy = 42; + | ^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-impl_trait_in_bindings.rs:13:13 + | +LL | static BAR: impl Copy = 42; + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0562`. diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs similarity index 100% rename from src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs rename to src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr similarity index 84% rename from src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr rename to src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr index c3f9abd90a7f1..22ca92bbe1391 100644 --- a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr +++ b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr @@ -1,5 +1,5 @@ error[E0411]: cannot find type `Self` in this scope - --> $DIR/feature-gate-self-in-typedefs.rs:13:17 + --> $DIR/feature-gate-self_in_typedefs.rs:13:17 | LL | Cons(T, &'a Self) | ^^^^ `Self` is only available in traits and impls From 8d5de0b1f804b55bd6043521de34705c737779d1 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 24 Sep 2018 04:25:23 +0100 Subject: [PATCH 3/5] Handle locals in closures properly. --- src/librustc/hir/def_id.rs | 2 +- src/librustc/hir/lowering.rs | 156 +++++++----------- src/librustc/infer/opaque_types/mod.rs | 13 +- .../borrow_check/nll/type_check/mod.rs | 9 +- src/librustc_typeck/check/mod.rs | 26 +-- 5 files changed, 83 insertions(+), 123 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index bbad157091b97..638591eb1fb69 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -215,7 +215,7 @@ impl DefIndexAddressSpace { } } -/// A DefId identifies a particular *definition*, by combining a crate +/// A `DefId` identifies a particular *definition*, by combining a crate /// index and a def index. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct DefId { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f25a17304f9ed..1e9936fdc13fc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -139,7 +139,6 @@ pub struct LoweringContext<'a> { type_def_lifetime_params: DefIdMap, current_hir_id_owner: Vec<(DefIndex, u32)>, - current_impl_trait_owner: Vec, item_local_id_counters: NodeMap, node_id_to_hir_id: IndexVec, } @@ -233,7 +232,6 @@ pub fn lower_crate( anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, type_def_lifetime_params: DefIdMap(), current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], - current_impl_trait_owner: vec![], item_local_id_counters: NodeMap(), node_id_to_hir_id: IndexVec::new(), is_generator: false, @@ -392,17 +390,6 @@ impl<'a> LoweringContext<'a> { } impl<'lcx, 'interner> ItemLowerer<'lcx, 'interner> { - fn with_impl_trait_owner(&mut self, def_id: DefId, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { - self.lctx.current_impl_trait_owner.push(def_id); - let ret = f(self); - self.lctx.current_impl_trait_owner.pop(); - - ret - } - fn with_trait_impl_ref(&mut self, trait_impl_ref: &Option, f: F) where F: FnOnce(&mut Self), @@ -440,12 +427,7 @@ impl<'a> LoweringContext<'a> { self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Fn(..) = item.node { - let fn_def_id = this.lctx.resolver.definitions().local_def_id(item.id); - this.with_impl_trait_owner(fn_def_id, |this| { - visit::walk_item(this, item) - }); - } else if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.node { + if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.node { this.with_trait_impl_ref(opt_trait_ref, |this| { visit::walk_item(this, item) }); @@ -573,17 +555,6 @@ impl<'a> LoweringContext<'a> { ret } - fn with_impl_trait_owner(&mut self, def_id: DefId, f: F) -> T - where - F: FnOnce(&mut LoweringContext) -> T, - { - self.current_impl_trait_owner.push(def_id); - let ret = f(self); - self.current_impl_trait_owner.pop(); - - ret - } - /// This method allocates a new HirId for the given NodeId and stores it in /// the LoweringContext's NodeId => HirId map. /// Take care not to call this method if the resulting HirId is then not @@ -1939,7 +1910,7 @@ impl<'a> LoweringContext<'a> { visitor.visit_ty(ty); } } - let impl_trait_owner_id = self.current_impl_trait_owner.last().map(|id| *id); + let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0); (P(hir::Local { id: node_id, hir_id, @@ -1947,7 +1918,7 @@ impl<'a> LoweringContext<'a> { .as_ref() .map(|t| self.lower_ty(t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::Existential(impl_trait_owner_id) + ImplTraitContext::Existential(Some(parent_def_id)) } else { ImplTraitContext::Disallowed } @@ -2213,8 +2184,7 @@ impl<'a> LoweringContext<'a> { span, Some(fn_def_id), return_impl_trait_id, |this| { let output_ty = match output { FunctionRetTy::Ty(ty) => { - let impl_trait_owner_id = *this.current_impl_trait_owner.last().unwrap(); - this.lower_ty(ty, ImplTraitContext::Existential(Some(impl_trait_owner_id))) + this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))) } FunctionRetTy::Default(span) => { let LoweredNodeId { node_id, hir_id } = this.next_id(); @@ -2738,33 +2708,31 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); - self.with_impl_trait_owner(fn_def_id, |this| { - this.with_new_scopes(|this| { - // Note: we don't need to change the return type from `T` to - // `impl Future` here because lower_body - // only cares about the input argument patterns in the function - // declaration (decl), not the return types. - let body_id = this.lower_async_body(decl, header.asyncness, body); - - let (generics, fn_decl) = this.add_in_band_defs( - generics, - fn_def_id, - AnonymousLifetimeMode::PassThrough, - |this, idty| this.lower_fn_decl( - decl, - Some((fn_def_id, idty)), - true, - header.asyncness.opt_return_id() - ), - ); + self.with_new_scopes(|this| { + // Note: we don't need to change the return type from `T` to + // `impl Future` here because lower_body + // only cares about the input argument patterns in the function + // declaration (decl), not the return types. + let body_id = this.lower_async_body(decl, header.asyncness, body); + + let (generics, fn_decl) = this.add_in_band_defs( + generics, + fn_def_id, + AnonymousLifetimeMode::PassThrough, + |this, idty| this.lower_fn_decl( + decl, + Some((fn_def_id, idty)), + true, + header.asyncness.opt_return_id() + ), + ); - hir::ItemKind::Fn( - fn_decl, - this.lower_fn_header(header), - generics, - body_id, - ) - }) + hir::ItemKind::Fn( + fn_decl, + this.lower_fn_header(header), + generics, + body_id, + ) }) } ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), @@ -3083,33 +3051,29 @@ impl<'a> LoweringContext<'a> { ), ), TraitItemKind::Method(ref sig, None) => { - self.with_impl_trait_owner(trait_item_def_id, |this| { - let names = this.lower_fn_args_to_names(&sig.decl); - let (generics, sig) = this.lower_method_sig( - &i.generics, - sig, - trait_item_def_id, - false, - None, - ); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) - }) + let names = self.lower_fn_args_to_names(&sig.decl); + let (generics, sig) = self.lower_method_sig( + &i.generics, + sig, + trait_item_def_id, + false, + None, + ); + (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) } TraitItemKind::Method(ref sig, Some(ref body)) => { - self.with_impl_trait_owner(trait_item_def_id, |this| { - let body_id = this.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) - }); - let (generics, sig) = this.lower_method_sig( - &i.generics, - sig, - trait_item_def_id, - false, - None, - ); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) - }) + let body_id = self.lower_body(Some(&sig.decl), |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); + let (generics, sig) = self.lower_method_sig( + &i.generics, + sig, + trait_item_def_id, + false, + None, + ); + (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) } TraitItemKind::Type(ref bounds, ref default) => ( self.lower_generics(&i.generics, ImplTraitContext::Disallowed), @@ -3175,18 +3139,16 @@ impl<'a> LoweringContext<'a> { ) } ImplItemKind::Method(ref sig, ref body) => { - self.with_impl_trait_owner(impl_item_def_id, |this| { - let body_id = this.lower_async_body(&sig.decl, sig.header.asyncness, body); - let impl_trait_return_allow = !this.is_in_trait_impl; - let (generics, sig) = this.lower_method_sig( - &i.generics, - sig, - impl_item_def_id, - impl_trait_return_allow, - sig.header.asyncness.opt_return_id(), - ); - (generics, hir::ImplItemKind::Method(sig, body_id)) - }) + let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness, body); + let impl_trait_return_allow = !self.is_in_trait_impl; + let (generics, sig) = self.lower_method_sig( + &i.generics, + sig, + impl_item_def_id, + impl_trait_return_allow, + sig.header.asyncness.opt_return_id(), + ); + (generics, hir::ImplItemKind::Method(sig, body_id)) } ImplItemKind::Type(ref ty) => ( self.lower_generics(&i.generics, ImplTraitContext::Disallowed), diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 74ea393d64ad7..88d375742670d 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -98,9 +98,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// # Parameters /// - /// - `parent_def_id` -- we will only instantiate opaque types - /// with this parent. This is typically the def-id of the function - /// in whose return type opaque types are being instantiated. + /// - `parent_def_id` -- the def-id of the function in which the opaque type + /// is defined /// - `body_id` -- the body-id with which the resulting obligations should /// be associated /// - `param_env` -- the in-scope parameter environment to be used for @@ -113,11 +112,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, value: &T, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { - debug!( - "instantiate_opaque_types(value={:?}, - parent_def_id={:?}, body_id={:?}, - param_env={:?})", - value, parent_def_id, body_id, param_env, + debug!("instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ + param_env={:?})", + value, parent_def_id, body_id, param_env, ); let mut instantiator = Instantiator { infcx: self, diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 8d260e0970add..70687d0efa402 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -898,7 +898,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - if let Err(terr) = self.sub_types(sub, sup, locations) { + if let Err(terr) = self.sub_types(sub, sup, locations, category) { if let TyKind::Opaque(..) = sup.sty { return self.eq_opaque_type_and_type(sub, sup, locations, category); } else { @@ -954,10 +954,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let infcx = self.infcx; let tcx = infcx.tcx; let param_env = self.param_env; - let mir_def_id = self.mir_def_id; + let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id); let opaque_type_map = self.fully_perform_op( locations, + category, CustomTypeOp::new( |infcx| { let mut obligations = ObligationAccumulator::default(); @@ -965,7 +966,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let dummy_body_id = ObligationCause::dummy().body_id; let (output_ty, opaque_type_map) = obligations.add(infcx.instantiate_opaque_types( - mir_def_id, + parent_def_id, dummy_body_id, param_env, &anon_ty, @@ -1028,7 +1029,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { for (opaque_def_id, opaque_decl) in opaque_type_map { self.fully_perform_op( locations, - category, + ConstraintCategory::OpaqueType, CustomTypeOp::new( |_cx| { infcx.constrain_opaque_type( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7265d82935b5e..5f6cc4c60c38c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -821,8 +821,8 @@ fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn used_trait_imports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Lrc { + def_id: DefId) + -> Lrc { tcx.typeck_tables_of(def_id).used_trait_imports.clone() } @@ -870,7 +870,6 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.require_type_is_sized(expected_type, body.value.span, traits::SizedReturnType); fcx.instantiate_opaque_types_from_value( id, &expected_type @@ -965,7 +964,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { let local_ty = match local.ty { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1); let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { self.fcx.instantiate_opaque_types_from_value( @@ -977,6 +975,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { }; let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty); + debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", + ty.hir_id, o_ty, revealed_ty, c_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); Some(LocalTy { decl_ty: o_ty, revealed_ty }) @@ -1074,7 +1074,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.yield_ty = Some(yield_ty); } - GatherLocalsVisitor { fcx: &fcx, parent_id: fn_id, }.visit_body(body); + let outer_def_id = fcx.tcx.closure_base_def_id(fcx.tcx.hir.local_def_id(fn_id)); + let outer_node_id = fcx.tcx.hir.as_local_node_id(outer_def_id).unwrap(); + GatherLocalsVisitor { fcx: &fcx, parent_id: outer_node_id, }.visit_body(body); // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { @@ -2265,19 +2267,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// `InferCtxt::instantiate_opaque_types` for more details. fn instantiate_opaque_types_from_value>( &self, - fn_id: ast::NodeId, + parent_id: ast::NodeId, value: &T, ) -> T { - let fn_def_id = self.tcx.hir.local_def_id(fn_id); - debug!( - "instantiate_opaque_types_from_value(fn_def_id={:?}, value={:?})", - fn_def_id, - value - ); + let parent_def_id = self.tcx.hir.local_def_id(parent_id); + debug!("instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", + parent_def_id, + value); let (value, opaque_type_map) = self.register_infer_ok_obligations( self.instantiate_opaque_types( - fn_def_id, + parent_def_id, self.body_id, self.param_env, value, From 3b1445022571b444ce45825c88ff59a1b80e1b37 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 11 Sep 2018 17:55:05 +0100 Subject: [PATCH 4/5] Added tests. --- src/test/run-pass/impl-trait-in-bindings.rs | 56 +++++++++++++++++++ src/test/ui/impl-trait/bindings-opaque.rs | 23 ++++++++ src/test/ui/impl-trait/bindings-opaque.stderr | 21 +++++++ src/test/ui/impl-trait/bindings.rs | 35 ++++++++++++ src/test/ui/impl-trait/bindings.stderr | 35 ++++++++++++ src/test/ui/impl-trait/where-allowed.rs | 1 - 6 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/impl-trait-in-bindings.rs create mode 100644 src/test/ui/impl-trait/bindings-opaque.rs create mode 100644 src/test/ui/impl-trait/bindings-opaque.stderr create mode 100644 src/test/ui/impl-trait/bindings.rs create mode 100644 src/test/ui/impl-trait/bindings.stderr diff --git a/src/test/run-pass/impl-trait-in-bindings.rs b/src/test/run-pass/impl-trait-in-bindings.rs new file mode 100644 index 0000000000000..631967c3f08b0 --- /dev/null +++ b/src/test/run-pass/impl-trait-in-bindings.rs @@ -0,0 +1,56 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(impl_trait_in_bindings)] + +use std::fmt::Debug; + +const FOO: impl Debug + Clone + PartialEq = 42; + +static BAR: impl Debug + Clone + PartialEq = 42; + +fn a(x: T) { + let y: impl Clone = x; + let _ = y.clone(); +} + +fn b(x: T) { + let f = move || { + let y: impl Clone = x; + let _ = y.clone(); + }; + f(); +} + +trait Foo { + fn a(x: T) { + let y: impl Clone = x; + let _ = y.clone(); + } +} + +impl Foo for i32 { + fn a(x: T) { + let y: impl Clone = x; + let _ = y.clone(); + } +} + +fn main() { + let foo: impl Debug + Clone + PartialEq = 42; + + assert_eq!(FOO.clone(), 42); + assert_eq!(BAR.clone(), 42); + assert_eq!(foo.clone(), 42); + + a(42); + b(42); + i32::a(42); +} diff --git a/src/test/ui/impl-trait/bindings-opaque.rs b/src/test/ui/impl-trait/bindings-opaque.rs new file mode 100644 index 0000000000000..88b7a52af7fd3 --- /dev/null +++ b/src/test/ui/impl-trait/bindings-opaque.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(impl_trait_in_bindings)] + +const FOO: impl Copy = 42; + +static BAR: impl Copy = 42; + +fn main() { + let foo: impl Copy = 42; + + let _ = FOO.count_ones(); + let _ = BAR.count_ones(); + let _ = foo.count_ones(); +} diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr new file mode 100644 index 0000000000000..00358ee502e86 --- /dev/null +++ b/src/test/ui/impl-trait/bindings-opaque.stderr @@ -0,0 +1,21 @@ +error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope + --> $DIR/bindings-opaque.rs:20:17 + | +LL | let _ = FOO.count_ones(); + | ^^^^^^^^^^ + +error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope + --> $DIR/bindings-opaque.rs:21:17 + | +LL | let _ = BAR.count_ones(); + | ^^^^^^^^^^ + +error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope + --> $DIR/bindings-opaque.rs:22:17 + | +LL | let _ = foo.count_ones(); + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/impl-trait/bindings.rs b/src/test/ui/impl-trait/bindings.rs new file mode 100644 index 0000000000000..571571aa75141 --- /dev/null +++ b/src/test/ui/impl-trait/bindings.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(impl_trait_in_bindings)] + +fn a(x: T) { + const foo: impl Clone = x; +} + +fn b(x: T) { + let _ = move || { + const foo: impl Clone = x; + }; +} + +trait Foo { + fn a(x: T) { + const foo: impl Clone = x; + } +} + +impl Foo for i32 { + fn a(x: T) { + const foo: impl Clone = x; + } +} + +fn main() { } diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr new file mode 100644 index 0000000000000..70a736d2fd18a --- /dev/null +++ b/src/test/ui/impl-trait/bindings.stderr @@ -0,0 +1,35 @@ +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/bindings.rs:14:29 + | +LL | const foo: impl Clone = x; + | ^ + | + = help: use the `|| { ... }` closure form instead + +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/bindings.rs:19:33 + | +LL | const foo: impl Clone = x; + | ^ + | + = help: use the `|| { ... }` closure form instead + +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/bindings.rs:25:33 + | +LL | const foo: impl Clone = x; + | ^ + | + = help: use the `|| { ... }` closure form instead + +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/bindings.rs:31:33 + | +LL | const foo: impl Clone = x; + | ^ + | + = help: use the `|| { ... }` closure form instead + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0434`. diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 69f6d202f14ad..4c5592c119c97 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -232,4 +232,3 @@ fn main() { let _in_return_in_local_variable = || -> impl Fn() { || {} }; //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types } - From 16cf404f9853e716a216be32d05f5215ff821c00 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Fri, 21 Sep 2018 01:24:52 +0100 Subject: [PATCH 5/5] Added section to Unstable Book. --- .../impl-trait-in-bindings.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md diff --git a/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md b/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md new file mode 100644 index 0000000000000..896465cf64978 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/impl-trait-in-bindings.md @@ -0,0 +1,28 @@ +# `impl_trait_in_bindings` + +The tracking issue for this feature is: [#34511] + +[#34511]: https://github.com/rust-lang/rust/issues/34511 + +------------------------ + +The `impl_trait_in_bindings` feature gate lets you use `impl Trait` syntax in +`let`, `static`, and `const` bindings. + +A simple example is: + +```rust +#![feature(impl_trait_in_bindings)] + +use std::fmt::Debug; + +fn main() { + let a: impl Debug + Clone = 42; + let b = a.clone(); + println!("{:?}", b); // prints `42` +} +``` + +Note however that because the types of `a` and `b` are opaque in the above +example, calling inherent methods or methods outside of the specified traits +(e.g., `a.abs()` or `b.abs()`) is not allowed, and yields an error.