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. diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3318bbd8c870e..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 return types. +allowed as function and inherent impl return types. Erroneous code example: diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index cd91b85689b30..638591eb1fb69 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, @@ -216,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 bd8770abb135c..1e9936fdc13fc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -175,15 +175,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, @@ -305,6 +307,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 @@ -396,7 +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::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) }); @@ -955,13 +986,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 { @@ -1224,12 +1255,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" + "`impl Trait` not allowed outside of {}", + allowed_in, ); hir::TyKind::Err } @@ -1250,7 +1287,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 +1307,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 +1328,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 +1901,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 parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0); + (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(Some(parent_def_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 +1998,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 +2181,11 @@ 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)), + FunctionRetTy::Ty(ty) => { + 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 { @@ -2629,18 +2680,34 @@ 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); - self.with_new_scopes(|this| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body @@ -2653,7 +2720,11 @@ impl<'a> LoweringContext<'a> { fn_def_id, AnonymousLifetimeMode::PassThrough, |this, idty| this.lower_fn_decl( - decl, Some((fn_def_id, idty)), true, header.asyncness.opt_return_id()), + decl, + Some((fn_def_id, idty)), + true, + header.asyncness.opt_return_id() + ), ); hir::ItemKind::Fn( @@ -2995,7 +3066,6 @@ impl<'a> LoweringContext<'a> { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); - let (generics, sig) = self.lower_method_sig( &i.generics, sig, @@ -3003,7 +3073,6 @@ impl<'a> LoweringContext<'a> { false, None, ); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) } TraitItemKind::Type(ref bounds, ref default) => ( @@ -3137,8 +3206,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 +3216,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,18 +3233,34 @@ 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 }, + 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 }], } } @@ -3761,8 +3820,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))) @@ -4312,15 +4371,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 +4410,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..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, @@ -736,7 +733,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 +805,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/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/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..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 @@ -14,18 +14,11 @@ //! 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; -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 a20d7cc561979..70687d0efa402 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}; @@ -98,7 +102,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 @@ -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, category) { + 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,112 @@ 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 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(); + + let dummy_body_id = ObligationCause::dummy().body_id; + let (output_ty, opaque_type_map) = + obligations.add(infcx.instantiate_opaque_types( + parent_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, + 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(), + ), + )?; + } + } + Ok(()) + } + fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx } @@ -942,7 +1073,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 +1366,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 +2235,7 @@ impl MirPass for TypeckMir { &[], None, None, + None, |_| (), ); @@ -2128,3 +2260,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/_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..5f6cc4c60c38c 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 @@ -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>>, @@ -815,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() } @@ -846,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 = @@ -863,10 +869,19 @@ 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.instantiate_opaque_types_from_value( + id, + &expected_type + ) + } else { + expected_type + }; + // 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); + fcx.check_expr_coercable_to_type(&body.value, revealed_ty); fcx }; @@ -914,22 +929,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 +961,34 @@ 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); - 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 = 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); + 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(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 +1005,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 +1056,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 +1074,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.yield_ty = Some(yield_ty); } - GatherLocalsVisitor { fcx: &fcx, }.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) { @@ -1274,90 +1305,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 */ } } } @@ -2040,7 +2077,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,25 +2262,22 @@ 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, + parent_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={:?})", - 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, @@ -2889,7 +2923,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 +3082,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 +3232,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 +3773,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 +3861,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 +3892,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; } } @@ -4083,7 +4117,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 +4505,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 +4524,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 +4861,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 +5102,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); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 43cb811ed0bbb..2faa38fd9f877 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -497,7 +497,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] @@ -508,13 +508,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/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/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 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 } -