diff --git a/src/doc/unstable-book/src/language-features/universal-impl-trait.md b/src/doc/unstable-book/src/language-features/universal-impl-trait.md new file mode 100644 index 0000000000000..6b3c5e92720df --- /dev/null +++ b/src/doc/unstable-book/src/language-features/universal-impl-trait.md @@ -0,0 +1,32 @@ +# `universal_impl_trait` + +The tracking issue for this feature is: [#34511]. + +[#34511]: https://github.com/rust-lang/rust/issues/34511 + +-------------------- + +The `universal_impl_trait` feature extends the [`conservative_impl_trait`] +feature allowing the `impl Trait` syntax in arguments (universal +quantification). + +[`conservative_impl_trait`]: ./language-features/conservative-impl-trait.html + +## Examples + +```rust +#![feature(universal_impl_trait)] +use std::ops::Not; + +fn any_zero(values: impl IntoIterator) -> bool { + for val in values { if val == 0 { return true; } } + false +} + +fn main() { + let test1 = -5..; + let test2 = vec![1, 8, 42, -87, 60]; + assert!(any_zero(test1)); + assert!(bool::not(any_zero(test2))); +} +``` diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2b6e1d855680d..bab3bded77b09 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1770,6 +1770,46 @@ If you want to get command-line arguments, use `std::env::args`. To exit with a 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. + +Erroneous code example: + +```compile_fail,E0562 +#![feature(conservative_impl_trait)] + +fn main() { + let count_to_ten: impl Iterator = 0..10; + // error: `impl Trait` not allowed outside of function and inherent method + // return types + for i in count_to_ten { + println!("{}", i); + } +} +``` + +Make sure `impl Trait` only appears in return-type position. + +``` +#![feature(conservative_impl_trait)] + +fn count_to_n(n: usize) -> impl Iterator { + 0..n +} + +fn main() { + for i in count_to_n(10) { // ok! + println!("{}", i); + } +} +``` + +See [RFC 1522] for more details. + +[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md +"##, + E0591: r##" Per [RFC 401][rfc401], if you have a function declaration `foo`: diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c23a5fb1f7ebb..84be68cb19765 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -591,7 +591,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } visitor.visit_lifetime(lifetime); } - TyImplTrait(ref bounds) => { + TyImplTraitExistential(ref bounds) => { + walk_list!(visitor, visit_ty_param_bound, bounds); + } + TyImplTraitUniversal(_, ref bounds) => { walk_list!(visitor, visit_ty_param_bound, bounds); } TyTypeof(expression) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ba89961adc687..8c9d1a38e7088 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -103,6 +103,7 @@ pub struct LoweringContext<'a> { catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, + is_in_trait_impl: bool, type_def_lifetime_params: DefIdMap, @@ -123,6 +124,24 @@ pub trait Resolver { fn definitions(&mut self) -> &mut Definitions; } +#[derive(Clone, Copy, Debug)] +enum ImplTraitContext { + /// Treat `impl Trait` as shorthand for a new universal generic parameter. + /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually + /// equivalent to a fresh universal parameter like `fn foo(x: T)`. + /// + /// We store a DefId here so we can look up necessary information later + Universal(DefId), + + /// Treat `impl Trait` as shorthand for a new universal 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`. + Existential, + + /// `impl Trait` is not accepted in this position. + Disallowed, +} + pub fn lower_crate(sess: &Session, cstore: &CrateStore, dep_graph: &DepGraph, @@ -156,6 +175,7 @@ pub fn lower_crate(sess: &Session, item_local_id_counters: NodeMap(), node_id_to_hir_id: IndexVec::new(), is_generator: false, + is_in_trait_impl: false, }.lower_crate(krate) } @@ -223,6 +243,21 @@ impl<'a> LoweringContext<'a> { lctx: &'lcx mut LoweringContext<'interner>, } + impl<'lcx, 'interner> ItemLowerer<'lcx, 'interner> { + fn with_trait_impl_ref(&mut self, trait_impl_ref: &Option, f: F) + where F: FnOnce(&mut Self) + { + let old = self.lctx.is_in_trait_impl; + self.lctx.is_in_trait_impl = if let &None = trait_impl_ref { + false + } else { + true + }; + f(self); + self.lctx.is_in_trait_impl = old; + } + } + impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { let mut item_lowered = true; @@ -235,7 +270,13 @@ impl<'a> LoweringContext<'a> { }); if item_lowered { - visit::walk_item(self, item); + if let ItemKind::Impl(_,_,_,_,ref opt_trait_ref,_,_) = item.node { + self.with_trait_impl_ref(opt_trait_ref, |this| { + visit::walk_item(this, item) + }); + } else { + visit::walk_item(self, item); + } } } @@ -644,48 +685,48 @@ impl<'a> LoweringContext<'a> { } } - fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding { + fn lower_ty_binding(&mut self, b: &TypeBinding, itctx: ImplTraitContext) -> hir::TypeBinding { hir::TypeBinding { id: self.lower_node_id(b.id).node_id, name: self.lower_ident(b.ident), - ty: self.lower_ty(&b.ty), + ty: self.lower_ty(&b.ty, itctx), span: b.span, } } - fn lower_ty(&mut self, t: &Ty) -> P { + fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P { let kind = match t.node { TyKind::Infer => hir::TyInfer, TyKind::Err => hir::TyErr, - TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), - TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), + TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty, itctx)), + TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { let span = t.span.with_hi(t.span.lo()); let lifetime = match *region { Some(ref lt) => self.lower_lifetime(lt), None => self.elided_lifetime(span) }; - hir::TyRptr(lifetime, self.lower_mt(mt)) + hir::TyRptr(lifetime, self.lower_mt(mt, itctx)) } TyKind::BareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { lifetimes: self.lower_lifetime_defs(&f.lifetimes), unsafety: self.lower_unsafety(f.unsafety), abi: f.abi, - decl: self.lower_fn_decl(&f.decl), + decl: self.lower_fn_decl(&f.decl, None, false), arg_names: self.lower_fn_args_to_names(&f.decl), })) } TyKind::Never => hir::TyNever, TyKind::Tup(ref tys) => { - hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) + hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty, itctx)).collect()) } TyKind::Paren(ref ty) => { - return self.lower_ty(ty); + return self.lower_ty(ty, itctx); } TyKind::Path(ref qself, ref path) => { let id = self.lower_node_id(t.id); - let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); + let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx); return self.ty_path(id, t.span, qpath); } TyKind::ImplicitSelf => { @@ -699,7 +740,7 @@ impl<'a> LoweringContext<'a> { } TyKind::Array(ref ty, ref length) => { let length = self.lower_body(None, |this| this.lower_expr(length)); - hir::TyArray(self.lower_ty(ty), length) + hir::TyArray(self.lower_ty(ty, itctx), length) } TyKind::Typeof(ref expr) => { let expr = self.lower_body(None, |this| this.lower_expr(expr)); @@ -710,7 +751,7 @@ impl<'a> LoweringContext<'a> { let bounds = bounds.iter().filter_map(|bound| { match *bound { TraitTyParamBound(ref ty, TraitBoundModifier::None) => { - Some(self.lower_poly_trait_ref(ty)) + Some(self.lower_poly_trait_ref(ty, itctx)) } TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, RegionTyParamBound(ref lifetime) => { @@ -727,7 +768,33 @@ impl<'a> LoweringContext<'a> { hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { - hir::TyImplTrait(self.lower_bounds(bounds)) + use syntax::feature_gate::{emit_feature_err, GateIssue}; + match itctx { + ImplTraitContext::Existential => { + let has_feature = self.sess.features.borrow().conservative_impl_trait; + if !t.span.allows_unstable() && !has_feature { + emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait", + t.span, GateIssue::Language, + "`impl Trait` in return position is experimental"); + } + hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx)) + }, + ImplTraitContext::Universal(def_id) => { + let has_feature = self.sess.features.borrow().universal_impl_trait; + if !t.span.allows_unstable() && !has_feature { + emit_feature_err(&self.sess.parse_sess, "universal_impl_trait", + t.span, GateIssue::Language, + "`impl Trait` in argument position is experimental"); + } + hir::TyImplTraitUniversal(def_id, self.lower_bounds(bounds, itctx)) + }, + ImplTraitContext::Disallowed => { + span_err!(self.sess, t.span, E0562, + "`impl Trait` not allowed outside of function \ + and inherent method return types"); + hir::TyErr + } + } } TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), }; @@ -773,10 +840,11 @@ impl<'a> LoweringContext<'a> { id: NodeId, qself: &Option, p: &Path, - param_mode: ParamMode) + param_mode: ParamMode, + itctx: ImplTraitContext) -> hir::QPath { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty)); + let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); let resolution = self.resolver.get_resolution(id) .unwrap_or(PathResolution::new(Def::Err)); @@ -846,7 +914,7 @@ impl<'a> LoweringContext<'a> { n }); self.lower_path_segment(p.span, segment, param_mode, num_lifetimes, - parenthesized_generic_args) + parenthesized_generic_args, itctx) }).collect(), span: p.span, }); @@ -882,7 +950,8 @@ impl<'a> LoweringContext<'a> { // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0, - ParenthesizedGenericArgs::Warn)); + ParenthesizedGenericArgs::Warn, + itctx)); let qpath = hir::QPath::TypeRelative(ty, segment); // It's finished, return the extension of the right node type. @@ -916,7 +985,8 @@ impl<'a> LoweringContext<'a> { def: self.expect_full_def(id), segments: segments.map(|segment| { self.lower_path_segment(p.span, segment, param_mode, 0, - ParenthesizedGenericArgs::Err) + ParenthesizedGenericArgs::Err, + ImplTraitContext::Disallowed) }).chain(name.map(|name| hir::PathSegment::from_name(name))) .collect(), span: p.span, @@ -937,16 +1007,18 @@ impl<'a> LoweringContext<'a> { segment: &PathSegment, param_mode: ParamMode, expected_lifetimes: usize, - parenthesized_generic_args: ParenthesizedGenericArgs) + parenthesized_generic_args: ParenthesizedGenericArgs, + itctx: ImplTraitContext) -> hir::PathSegment { let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters { let msg = "parenthesized parameters may only be used with a trait"; match **parameters { PathParameters::AngleBracketed(ref data) => { - self.lower_angle_bracketed_parameter_data(data, param_mode) + self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } PathParameters::Parenthesized(ref data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), + ParenthesizedGenericArgs::Ok => + self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Warn => { self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, CRATE_NODE_ID, data.span, msg.into()); @@ -960,7 +1032,7 @@ impl<'a> LoweringContext<'a> { } } } else { - self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode) + self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx) }; if !parameters.parenthesized && parameters.lifetimes.is_empty() { @@ -978,13 +1050,14 @@ impl<'a> LoweringContext<'a> { fn lower_angle_bracketed_parameter_data(&mut self, data: &AngleBracketedParameterData, - param_mode: ParamMode) + param_mode: ParamMode, + itctx: ImplTraitContext) -> (hir::PathParameters, bool) { let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data; (hir::PathParameters { lifetimes: self.lower_lifetimes(lifetimes), - types: types.iter().map(|ty| self.lower_ty(ty)).collect(), - bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(), + types: types.iter().map(|ty| self.lower_ty(ty, itctx)).collect(), + bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(), parenthesized: false, }, types.is_empty() && param_mode == ParamMode::Optional) } @@ -992,8 +1065,9 @@ impl<'a> LoweringContext<'a> { fn lower_parenthesized_parameter_data(&mut self, data: &ParenthesizedParameterData) -> (hir::PathParameters, bool) { + const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed; let &ParenthesizedParameterData { ref inputs, ref output, span } = data; - let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect(); + let inputs = inputs.iter().map(|ty| self.lower_ty(ty, DISALLOWED)).collect(); let mk_tup = |this: &mut Self, tys, span| { let LoweredNodeId { node_id, hir_id } = this.next_id(); P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span }) @@ -1005,7 +1079,7 @@ impl<'a> LoweringContext<'a> { bindings: hir_vec![hir::TypeBinding { id: self.next_id().node_id, name: Symbol::intern(FN_OUTPUT_NAME), - ty: output.as_ref().map(|ty| self.lower_ty(&ty)) + ty: output.as_ref().map(|ty| self.lower_ty(&ty, DISALLOWED)) .unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)), span: output.as_ref().map_or(span, |ty| ty.span), }], @@ -1018,7 +1092,7 @@ impl<'a> LoweringContext<'a> { P(hir::Local { id: node_id, hir_id, - ty: l.ty.as_ref().map(|t| self.lower_ty(t)), + ty: l.ty.as_ref().map(|t| self.lower_ty(t, ImplTraitContext::Disallowed)), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), span: l.span, @@ -1055,11 +1129,32 @@ impl<'a> LoweringContext<'a> { }).collect() } - fn lower_fn_decl(&mut self, decl: &FnDecl) -> P { + + fn lower_fn_decl(&mut self, + decl: &FnDecl, + fn_def_id: Option, + impl_trait_return_allow: bool) + -> P { + // NOTE: The two last paramters here have to do with impl Trait. If fn_def_id is Some, + // then impl Trait arguments are lowered into generic paramters on the given + // fn_def_id, otherwise impl Trait is disallowed. (for now) + // + // Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in + // return positions as well. This guards against trait declarations and their impls + // where impl Trait is disallowed. (again for now) P(hir::FnDecl { - inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(), + inputs: decl.inputs.iter() + .map(|arg| if let Some(def_id) = fn_def_id { + self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id)) + } else { + self.lower_ty(&arg.ty, ImplTraitContext::Disallowed) + }).collect(), output: match decl.output { - FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)), + FunctionRetTy::Ty(ref ty) => match fn_def_id { + Some(_) if impl_trait_return_allow => + hir::Return(self.lower_ty(ty, ImplTraitContext::Existential)), + _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), + }, FunctionRetTy::Default(span) => hir::DefaultReturn(span), }, variadic: decl.variadic, @@ -1073,10 +1168,11 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_ty_param_bound(&mut self, tpb: &TyParamBound) -> hir::TyParamBound { + fn lower_ty_param_bound(&mut self, tpb: &TyParamBound, itctx: ImplTraitContext) + -> hir::TyParamBound { match *tpb { TraitTyParamBound(ref ty, modifier) => { - hir::TraitTyParamBound(self.lower_poly_trait_ref(ty), + hir::TraitTyParamBound(self.lower_poly_trait_ref(ty, itctx), self.lower_trait_bound_modifier(modifier)) } RegionTyParamBound(ref lifetime) => { @@ -1095,16 +1191,19 @@ impl<'a> LoweringContext<'a> { name = Symbol::gensym("Self"); } - let mut bounds = self.lower_bounds(&tp.bounds); + let itctx = ImplTraitContext::Universal(self.resolver.definitions().local_def_id(tp.id)); + let mut bounds = self.lower_bounds(&tp.bounds, itctx); if !add_bounds.is_empty() { - bounds = bounds.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect(); + bounds = bounds.into_iter().chain( + self.lower_bounds(add_bounds, itctx).into_iter() + ).collect(); } hir::TyParam { id: self.lower_node_id(tp.id).node_id, name, bounds, - default: tp.default.as_ref().map(|x| self.lower_ty(x)), + default: tp.default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)), span: tp.span, pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), synthetic: tp.attrs.iter() @@ -1215,11 +1314,11 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes), - bounded_ty: self.lower_ty(bounded_ty), + bounded_ty: self.lower_ty(bounded_ty, ImplTraitContext::Disallowed), bounds: bounds.iter().filter_map(|bound| match *bound { // Ignore `?Trait` bounds, they were copied into type parameters already. TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, - _ => Some(self.lower_ty_param_bound(bound)) + _ => Some(self.lower_ty_param_bound(bound, ImplTraitContext::Disallowed)) }).collect(), span, }) @@ -1239,8 +1338,8 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: self.lower_node_id(id).node_id, - lhs_ty: self.lower_ty(lhs_ty), - rhs_ty: self.lower_ty(rhs_ty), + lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::Disallowed), + rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::Disallowed), span, }) } @@ -1267,8 +1366,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { - let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) { + fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef { + let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) { hir::QPath::Resolved(None, path) => path.and_then(|path| path), qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath) }; @@ -1278,10 +1377,13 @@ impl<'a> LoweringContext<'a> { } } - fn lower_poly_trait_ref(&mut self, p: &PolyTraitRef) -> hir::PolyTraitRef { + fn lower_poly_trait_ref(&mut self, + p: &PolyTraitRef, + itctx: ImplTraitContext) + -> hir::PolyTraitRef { hir::PolyTraitRef { bound_lifetimes: self.lower_lifetime_defs(&p.bound_lifetimes), - trait_ref: self.lower_trait_ref(&p.trait_ref), + trait_ref: self.lower_trait_ref(&p.trait_ref, itctx), span: p.span, } } @@ -1296,7 +1398,7 @@ impl<'a> LoweringContext<'a> { None => Ident { name: Symbol::intern(&index.to_string()), ctxt: f.span.ctxt() }, }), vis: self.lower_visibility(&f.vis, None), - ty: self.lower_ty(&f.ty), + ty: self.lower_ty(&f.ty, ImplTraitContext::Disallowed), attrs: self.lower_attrs(&f.attrs), } } @@ -1310,15 +1412,16 @@ impl<'a> LoweringContext<'a> { } } - fn lower_mt(&mut self, mt: &MutTy) -> hir::MutTy { + fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy { hir::MutTy { - ty: self.lower_ty(&mt.ty), + ty: self.lower_ty(&mt.ty, itctx), mutbl: self.lower_mutability(mt.mutbl), } } - fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds { - bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() + fn lower_bounds(&mut self, bounds: &[TyParamBound], itctx: ImplTraitContext) + -> hir::TyParamBounds { + bounds.iter().map(|bound| self.lower_ty_param_bound(bound, itctx)).collect() } fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { @@ -1437,33 +1540,35 @@ impl<'a> LoweringContext<'a> { } ItemKind::Static(ref t, m, ref e) => { let value = self.lower_body(None, |this| this.lower_expr(e)); - hir::ItemStatic(self.lower_ty(t), + hir::ItemStatic(self.lower_ty(t, 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::ItemConst(self.lower_ty(t), value) + hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + let fn_def_id = self.resolver.definitions().opt_local_def_id(id); self.with_new_scopes(|this| { let body_id = this.lower_body(Some(decl), |this| { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); - hir::ItemFn(this.lower_fn_decl(decl), - this.lower_unsafety(unsafety), - this.lower_constness(constness), - abi, - this.lower_generics(generics), - body_id) + hir::ItemFn(this.lower_fn_decl(decl, fn_def_id, true), + this.lower_unsafety(unsafety), + this.lower_constness(constness), + abi, + this.lower_generics(generics), + body_id) }) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)), ItemKind::Ty(ref t, ref generics) => { - hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) + hir::ItemTy(self.lower_ty(t, ImplTraitContext::Disallowed), + self.lower_generics(generics)) } ItemKind::Enum(ref enum_definition, ref generics) => { hir::ItemEnum(hir::EnumDef { @@ -1483,7 +1588,7 @@ impl<'a> LoweringContext<'a> { hir::ItemUnion(vdata, self.lower_generics(generics)) } ItemKind::AutoImpl(unsafety, ref trait_ref) => { - let trait_ref = self.lower_trait_ref(trait_ref); + let trait_ref = self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed); if let Def::Trait(def_id) = trait_ref.path.def { self.trait_auto_impl.insert(def_id, id); @@ -1502,7 +1607,9 @@ impl<'a> LoweringContext<'a> { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); - let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); + let ifce = ifce.as_ref().map(|trait_ref| { + self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed) + }); if let Some(ref trait_ref) = ifce { if let Def::Trait(def_id) = trait_ref.path.def { @@ -1515,11 +1622,11 @@ impl<'a> LoweringContext<'a> { self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, - self.lower_ty(ty), + self.lower_ty(ty, ImplTraitContext::Disallowed), new_impl_items) } ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => { - let bounds = self.lower_bounds(bounds); + let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed); let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect(); hir::ItemTrait(self.lower_is_auto(is_auto), self.lower_unsafety(unsafety), @@ -1537,6 +1644,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { self.with_parent_def(i.id, |this| { let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id); + let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id); hir::TraitItem { id: node_id, @@ -1546,14 +1654,14 @@ impl<'a> LoweringContext<'a> { generics: this.lower_generics(&i.generics), node: match i.node { TraitItemKind::Const(ref ty, ref default) => { - hir::TraitItemKind::Const(this.lower_ty(ty), + hir::TraitItemKind::Const(this.lower_ty(ty, ImplTraitContext::Disallowed), default.as_ref().map(|x| { this.lower_body(None, |this| this.lower_expr(x)) })) } TraitItemKind::Method(ref sig, None) => { let names = this.lower_fn_args_to_names(&sig.decl); - hir::TraitItemKind::Method(this.lower_method_sig(sig), + hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false), hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { @@ -1561,12 +1669,15 @@ impl<'a> LoweringContext<'a> { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); - hir::TraitItemKind::Method(this.lower_method_sig(sig), + hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false), hir::TraitMethod::Provided(body_id)) } TraitItemKind::Type(ref bounds, ref default) => { - hir::TraitItemKind::Type(this.lower_bounds(bounds), - default.as_ref().map(|x| this.lower_ty(x))) + hir::TraitItemKind::Type(this.lower_bounds(bounds, + ImplTraitContext::Disallowed), + default.as_ref().map(|x| { + this.lower_ty(x, ImplTraitContext::Disallowed) + })) } TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"), }, @@ -1602,6 +1713,7 @@ impl<'a> LoweringContext<'a> { fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { self.with_parent_def(i.id, |this| { let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id); + let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id); hir::ImplItem { id: node_id, @@ -1614,16 +1726,24 @@ impl<'a> LoweringContext<'a> { node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { let body_id = this.lower_body(None, |this| this.lower_expr(expr)); - hir::ImplItemKind::Const(this.lower_ty(ty), body_id) + hir::ImplItemKind::Const( + this.lower_ty(ty, ImplTraitContext::Disallowed), + body_id + ) } ImplItemKind::Method(ref sig, ref body) => { let body_id = this.lower_body(Some(&sig.decl), |this| { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); - hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) + let impl_trait_return_allow = !this.is_in_trait_impl; + hir::ImplItemKind::Method(this.lower_method_sig(sig, + fn_def_id, + impl_trait_return_allow), + body_id) } - ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), + ImplItemKind::Type(ref ty) => + hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)), ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), }, span: i.span, @@ -1643,8 +1763,10 @@ impl<'a> LoweringContext<'a> { kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, - ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method { - has_self: sig.decl.has_self(), + ImplItemKind::Method(ref sig, _) => { + hir::AssociatedItemKind::Method { + has_self: sig.decl.has_self(), + } }, ImplItemKind::Macro(..) => unimplemented!(), }, @@ -1719,12 +1841,13 @@ impl<'a> LoweringContext<'a> { attrs: this.lower_attrs(&i.attrs), node: match i.node { ForeignItemKind::Fn(ref fdec, ref generics) => { - hir::ForeignItemFn(this.lower_fn_decl(fdec), + // Disallow impl Trait in foreign items + hir::ForeignItemFn(this.lower_fn_decl(fdec, None, false), this.lower_fn_args_to_names(fdec), this.lower_generics(generics)) } ForeignItemKind::Static(ref t, m) => { - hir::ForeignItemStatic(this.lower_ty(t), m) + hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m) } ForeignItemKind::Ty => { hir::ForeignItemType @@ -1736,12 +1859,16 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { + fn lower_method_sig(&mut self, + sig: &MethodSig, + fn_def_id: Option, + impl_trait_return_allow: bool) + -> hir::MethodSig { hir::MethodSig { abi: sig.abi, unsafety: self.lower_unsafety(sig.unsafety), constness: self.lower_constness(sig.constness), - decl: self.lower_fn_decl(&sig.decl), + decl: self.lower_fn_decl(&sig.decl, fn_def_id, impl_trait_return_allow), } } @@ -1834,16 +1961,19 @@ impl<'a> LoweringContext<'a> { } PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))), PatKind::TupleStruct(ref path, ref pats, ddpos) => { - let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional); + let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional, + ImplTraitContext::Disallowed); hir::PatKind::TupleStruct(qpath, pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } PatKind::Path(ref qself, ref path) => { - hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional)) + hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional, + ImplTraitContext::Disallowed)) } PatKind::Struct(ref path, ref fields, etc) => { - let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional); + let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional, + ImplTraitContext::Disallowed); let fs = fields.iter() .map(|f| { @@ -2020,7 +2150,8 @@ impl<'a> LoweringContext<'a> { } ExprKind::MethodCall(ref seg, ref args) => { let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0, - ParenthesizedGenericArgs::Err); + ParenthesizedGenericArgs::Err, + ImplTraitContext::Disallowed); let args = args.iter().map(|x| self.lower_expr(x)).collect(); hir::ExprMethodCall(hir_seg, seg.span, args) } @@ -2038,11 +2169,11 @@ impl<'a> LoweringContext<'a> { ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), ExprKind::Cast(ref expr, ref ty) => { let expr = P(self.lower_expr(expr)); - hir::ExprCast(expr, self.lower_ty(ty)) + hir::ExprCast(expr, self.lower_ty(ty, ImplTraitContext::Disallowed)) } ExprKind::Type(ref expr, ref ty) => { let expr = P(self.lower_expr(expr)); - hir::ExprType(expr, self.lower_ty(ty)) + hir::ExprType(expr, self.lower_ty(ty, ImplTraitContext::Disallowed)) } ExprKind::AddrOf(m, ref ohs) => { let m = self.lower_mutability(m); @@ -2119,7 +2250,7 @@ impl<'a> LoweringContext<'a> { this.sess.abort_if_errors(); } hir::ExprClosure(this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl), + this.lower_fn_decl(decl, None, false), body_id, fn_decl_span, is_generator) @@ -2193,7 +2324,8 @@ impl<'a> LoweringContext<'a> { }; } ExprKind::Path(ref qself, ref path) => { - hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional)) + hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional, + ImplTraitContext::Disallowed)) } ExprKind::Break(opt_ident, ref opt_expr) => { let label_result = if self.is_in_loop_condition && opt_ident.is_none() { @@ -2246,7 +2378,8 @@ impl<'a> LoweringContext<'a> { hir::ExprInlineAsm(P(hir_asm), outputs, inputs) } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional), + hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional, + ImplTraitContext::Disallowed), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| P(self.lower_expr(x)))) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index a7206f5d420a5..ee83000c44003 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1461,9 +1461,12 @@ pub enum Ty_ { /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TyTraitObject(HirVec, Lifetime), - /// An `impl Bound1 + Bound2 + Bound3` type - /// where `Bound` is a trait or a lifetime. - TyImplTrait(TyParamBounds), + /// An exsitentially quantified (there exists a type satisfying) `impl + /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime. + TyImplTraitExistential(TyParamBounds), + /// An universally quantified (for all types satisfying) `impl + /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime. + TyImplTraitUniversal(DefId, TyParamBounds), /// Unused for now TyTypeof(BodyId), /// TyInfer means the type should be inferred instead of it having been diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 7d0f26ba34d41..451e870f500dd 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -421,8 +421,9 @@ impl<'a> State<'a> { self.print_lifetime(lifetime)?; } } - hir::TyImplTrait(ref bounds) => { - self.print_bounds("impl ", &bounds[..])?; + hir::TyImplTraitExistential(ref bounds) | + hir::TyImplTraitUniversal(_, ref bounds) => { + self.print_bounds("impl", &bounds[..])?; } hir::TyArray(ref ty, v) => { self.s.word("[")?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 6b78cd473be8f..a04683e1b2200 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -287,7 +287,8 @@ impl_stable_hash_for!(enum hir::Ty_ { TyTup(ts), TyPath(qpath), TyTraitObject(trait_refs, lifetime), - TyImplTrait(bounds), + TyImplTraitExistential(bounds), + TyImplTraitUniversal(def_id, bounds), TyTypeof(body_id), TyErr, TyInfer diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ffd06ee8a2e3a..8c299612064d5 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1604,6 +1604,17 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, walk_list!(&mut appears_in_where_clause, visit_where_predicate, &generics.where_clause.predicates); + // We need to collect argument impl Trait lifetimes as well, + // we do so here. + walk_list!(&mut appears_in_where_clause, + visit_ty, + decl.inputs.iter().filter(|ty| { + if let hir::TyImplTraitUniversal(..) = ty.node { + true + } else { + false + } + })); for lifetime_def in &generics.lifetimes { if !lifetime_def.bounds.is_empty() { // `'a: 'b` means both `'a` and `'b` are referenced @@ -1698,7 +1709,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, } fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyImplTrait(_) = ty.node { + if let hir::TyImplTraitExistential(_) = ty.node { self.impl_trait = true; } intravisit::walk_ty(self, ty); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d5eee14bf506b..8c40f303b939a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1487,7 +1487,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty(&mut self, ty: &hir::Ty) { match ty.node { - hir::TyImplTrait(_) => { + hir::TyImplTraitExistential(_) => { let def_id = self.tcx.hir.local_def_id(ty.id); self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 630260feed789..74d92ce1c3e62 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTrait(..) = ty.node { + if let hir::TyImplTraitExistential(..) = ty.node { if self.get(ty.id).is_some() { // Reach the (potentially private) type and the API being exposed. self.reach(ty.id).ty().predicates(); @@ -1557,7 +1557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTrait(..) = ty.node { + if let hir::TyImplTraitExistential(..) = ty.node { // Check the traits being exposed, as they're separate, // e.g. `impl Iterator` has two predicates, // `X: Iterator` and `::Item == T`, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 95b19616e5e63..7aaf65e1fd07d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -30,6 +30,7 @@ use util::nodemap::FxHashSet; use std::iter; use syntax::{abi, ast}; +use syntax::symbol::Symbol; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::Span; @@ -1033,53 +1034,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyTraitObject(ref bounds, ref lifetime) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } - hir::TyImplTrait(_) => { - // Figure out if we can allow an `impl Trait` here, by walking up - // to a `fn` or inherent `impl` method, going only through `Ty` - // or `TraitRef` nodes (as nothing else should be in types) and - // ensuring that we reach the `fn`/method signature's return type. - let mut node_id = ast_ty.id; - let fn_decl = loop { - let parent = tcx.hir.get_parent_node(node_id); - match tcx.hir.get(parent) { - hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(ref fn_decl, ..), .. - }) => break Some(fn_decl), - - hir::map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(ref sig, _), .. - }) => { - match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node { - hir::ItemImpl(.., None, _, _) => { - break Some(&sig.decl) - } - _ => break None - } - } - - hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {} - - _ => break None - } - node_id = parent; - }; - let allow = fn_decl.map_or(false, |fd| { - match fd.output { - hir::DefaultReturn(_) => false, - hir::Return(ref ty) => ty.id == node_id - } - }); - - // Create the anonymized type. - if allow { - let def_id = tcx.hir.local_def_id(ast_ty.id); - tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id)) - } else { - span_err!(tcx.sess, ast_ty.span, E0562, - "`impl Trait` not allowed outside of function \ - and inherent method return types"); - tcx.types.err - } + hir::TyImplTraitExistential(_) => { + let def_id = tcx.hir.local_def_id(ast_ty.id); + tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id)) + } + hir::TyImplTraitUniversal(fn_def_id, _) => { + let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id); + let generics = tcx.generics_of(fn_def_id); + let index = generics.type_param_to_index[&impl_trait_def_id.index]; + tcx.mk_param(index, + Symbol::intern(&tcx.hir.node_to_pretty_string(ast_ty.id))) } hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2c44c40d83d49..139449e5ab0ae 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -67,6 +67,14 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } + if let Err(ErrorReported) = compare_synthetic_generics(tcx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { + return; + } + if let Err(ErrorReported) = compare_predicate_entailment(tcx, impl_m, impl_m_span, @@ -708,6 +716,45 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } +fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_m: &ty::AssociatedItem, + _impl_m_span: Span, // FIXME necessary? + trait_m: &ty::AssociatedItem, + _trait_item_span: Option) // FIXME necessary? + -> Result<(), ErrorReported> { + // FIXME(chrisvittal) Clean up this function, list of FIXME items: + // 1. Better messages for the span lables + // 2. Explanation as to what is going on + // 3. Correct the function signature for what we actually use + // If we get here, we already have the same number of generics, so the zip will + // be okay. + let mut error_found = false; + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); + for (impl_ty, trait_ty) in impl_m_generics.types.iter().zip(trait_m_generics.types.iter()) { + if impl_ty.synthetic != trait_ty.synthetic { + let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap(); + let impl_span = tcx.hir.span(impl_node_id); + let trait_node_id = tcx.hir.as_local_node_id(trait_ty.def_id).unwrap(); + let trait_span = tcx.hir.span(trait_node_id); + let mut err = struct_span_err!(tcx.sess, + impl_span, + E0643, + "method `{}` has incompatible signature for trait", + trait_m.name); + err.span_label(trait_span, "annotation in trait"); + err.span_label(impl_span, "annotation in impl"); + err.emit(); + error_found = true; + } + } + if error_found { + Err(ErrorReported) + } else { + Ok(()) + } +} + pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_c: &ty::AssociatedItem, impl_c_span: Span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82d59ecfc92cf..4cc1e83d6e3c9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5035,6 +5035,10 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty { debug!("Found use of ty param num {}", idx); tps_used[idx as usize - generics.lifetimes.len()] = true; + } else if let ty::TyError = leaf_ty.sty { + // If there already another error, do not emit an error for not using a type Parameter + assert!(tcx.sess.err_count() > 0); + return; } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 814470974285f..b5fbbeb1692e6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -43,6 +43,7 @@ use rustc_const_math::ConstInt; use std::collections::BTreeMap; use syntax::{abi, ast}; +use syntax::ptr::P; use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; use syntax_pos::{Span, DUMMY_SP}; @@ -130,7 +131,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTrait(..) = ty.node { + if let hir::TyImplTraitExistential(..) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); self.tcx.generics_of(def_id); self.tcx.predicates_of(def_id); @@ -854,7 +855,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { Some(tcx.closure_base_def_id(def_id)) } - NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => { + NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => { let mut parent_id = node_id; loop { match tcx.hir.get(parent_id) { @@ -873,22 +874,32 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut allow_defaults = false; let no_generics = hir::Generics::empty(); - let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + let (ast_generics, opt_inputs) = match node { + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } - NodeImplItem(item) => &item.generics, + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } NodeItem(item) => { match item.node { - ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) => generics, + ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)), + ItemImpl(_, _, _, ref generics, ..) => (generics, None), ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => { allow_defaults = true; - generics + (generics, None) } ItemTrait(_, _, ref generics, ..) => { @@ -909,22 +920,22 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); allow_defaults = true; - generics + (generics, None) } - _ => &no_generics + _ => (&no_generics, None) } } NodeForeignItem(item) => { match item.node { - ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics, - ForeignItemType => &no_generics, + ForeignItemStatic(..) => (&no_generics, None), + ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)), + ForeignItemType => (&no_generics, None) } } - _ => &no_generics + _ => (&no_generics, None) }; let has_self = opt_self.is_some(); @@ -981,7 +992,24 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, synthetic: p.synthetic, } }); - let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); + + let fn_ins = opt_inputs.map(|tys| &tys[..]); + let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins); + let other_type_start = type_start + ast_generics.ty_params.len() as u32; + let mut types: Vec<_> = opt_self.into_iter() + .chain(types) + .chain(univ_impl_trait_info.iter().enumerate().map(|(i, info)| { + ty::TypeParameterDef { + index: other_type_start + i as u32, + name: Symbol::intern(&tcx.hir.node_to_pretty_string(info.id)), + def_id: info.def_id, + has_default: false, + object_lifetime_default: rl::Set1::Empty, + pure_wrt_drop: false, + synthetic: Some(SyntheticTyParamKind::ImplTrait), + } + })) + .collect(); // provide junk type parameter defs - the only place that // cares about anything but the length is instantiation, @@ -1155,7 +1183,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, icx.to_ty(ty) } - NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => { + NodeTy(&hir::Ty { node: TyImplTraitExistential(..), .. }) => { let owner = tcx.hir.get_parent_did(node_id); let hir_id = tcx.hir.node_to_hir_id(node_id); tcx.typeck_tables_of(owner).node_id_to_type(hir_id) @@ -1337,20 +1365,31 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); - let ast_generics = match node { - NodeTraitItem(item) => &item.generics, + let (ast_generics, opt_inputs) = match node { + NodeTraitItem(item) => { + match item.node { + TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } - NodeImplItem(item) => &item.generics, + NodeImplItem(item) => { + match item.node { + ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + _ => (&item.generics, None) + } + } NodeItem(item) => { match item.node { - ItemFn(.., ref generics, _) | + ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)), + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => { - generics + (generics, None) } ItemTrait(_, _, ref generics, .., ref items) => { @@ -1358,22 +1397,22 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id, substs: Substs::identity_for_item(tcx, def_id) }, items)); - generics + (generics, None) } - _ => &no_generics + _ => (&no_generics, None) } } NodeForeignItem(item) => { match item.node { - ForeignItemStatic(..) => &no_generics, - ForeignItemFn(_, _, ref generics) => generics, - ForeignItemType => &no_generics, + ForeignItemStatic(..) => (&no_generics, None), + ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)), + ForeignItemType => (&no_generics, None), } } - NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => { + NodeTy(&Ty { node: TyImplTraitExistential(ref bounds), span, .. }) => { let substs = Substs::identity_for_item(tcx, def_id); let anon_ty = tcx.mk_anon(def_id, substs); @@ -1387,7 +1426,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; } - _ => &no_generics + _ => (&no_generics, None) }; let generics = tcx.generics_of(def_id); @@ -1518,6 +1557,19 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })) } + // Add predicates from impl Trait arguments + let fn_ins = opt_inputs.map(|tys| &tys[..]); + let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins); + for info in univ_impl_trait_info.iter() { + let name = keywords::Invalid.name(); + let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); + index += 1; + let bounds = compute_bounds(&icx, param_ty, info.bounds, + SizedByDefault::Yes, + info.span); + predicates.extend(bounds.predicates(tcx, param_ty)); + } + // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come // before uses of `U`. This avoids false ambiguity errors @@ -1678,3 +1730,54 @@ fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => bug!("is_auto_impl applied to non-local def-id {:?}", def_id) } } + +struct ImplTraitUniversalInfo<'hir> { + id: ast::NodeId, + def_id: DefId, + span: Span, + bounds: &'hir [hir::TyParamBound], +} + +/// Take some possible list of arguments and return the DefIds of the ImplTraitUniversal +/// arguments +fn extract_universal_impl_trait_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + opt_inputs: Option<&'tcx [P]>) + -> Vec> +{ + // A visitor for simply collecting Universally quantified impl Trait arguments + struct ImplTraitUniversalVisitor<'tcx> { + items: Vec<&'tcx hir::Ty> + } + + impl<'tcx> Visitor<'tcx> for ImplTraitUniversalVisitor<'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &'tcx hir::Ty) { + if let hir::TyImplTraitUniversal(..) = ty.node { + self.items.push(ty); + } + intravisit::walk_ty(self, ty); + } + } + + let mut visitor = ImplTraitUniversalVisitor { items: Vec::new() }; + + if let Some(inputs) = opt_inputs { + for t in inputs.iter() { + visitor.visit_ty(t); + } + } + + visitor.items.into_iter().map(|ty| if let hir::TyImplTraitUniversal(_, ref bounds) = ty.node { + ImplTraitUniversalInfo { + id: ty.id, + def_id: tcx.hir.local_def_id(ty.id), + span: ty.span, + bounds: bounds + } + } else { + span_bug!(ty.span, "this type should be a universally quantified impl trait. this is a bug") + }).collect() +} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 73bec697d492e..328b7f9fdefca 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3818,46 +3818,6 @@ let s = Simba { mother: 1, father: 0 }; // ok! ``` "##, -E0562: r##" -Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function return types. - -Erroneous code example: - -```compile_fail,E0562 -#![feature(conservative_impl_trait)] - -fn main() { - let count_to_ten: impl Iterator = 0..10; - // error: `impl Trait` not allowed outside of function and inherent method - // return types - for i in count_to_ten { - println!("{}", i); - } -} -``` - -Make sure `impl Trait` only appears in return-type position. - -``` -#![feature(conservative_impl_trait)] - -fn count_to_n(n: usize) -> impl Iterator { - 0..n -} - -fn main() { - for i in count_to_n(10) { // ok! - println!("{}", i); - } -} -``` - -See [RFC 1522] for more details. - -[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md -"##, - E0569: r##" If an impl has a generic parameter with the `#[may_dangle]` attribute, then that impl must be declared as an `unsafe impl. @@ -4665,6 +4625,22 @@ It is recommended that you look for a `new` function or equivalent in the crate's documentation. "##, +E0643: r##" +This error indicates that there is a mismatch between generic parameters and +impl Trait parameters in a trait declaration versus its impl. + +```compile_fail,E0643 +#![feature(universal_impl_trait)] +trait Foo { + fn foo(&self, _: &impl Iterator); +} +impl Foo for () { + fn foo(&self, _: &U) { } // error method `foo` has incompatible + // signature for trait +} +``` +"##, + } register_diagnostics! { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4b60536e1d176..1d107c169b046 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1960,7 +1960,9 @@ impl Clean for hir::Ty { } } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), - TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)), + TyImplTraitExistential(ref bounds) | + TyImplTraitUniversal(_, ref bounds) => + ImplTrait(bounds.clean(cx)), TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b6cb3ac13081f..97eec3a21e9d1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -275,6 +275,9 @@ declare_features! ( // Allows `impl Trait` in function return types. (active, conservative_impl_trait, "1.12.0", Some(34511)), + // Allows `impl Trait` in function arguments. + (active, universal_impl_trait, "1.23.0", Some(34511)), + // The `!` type (active, never_type, "1.13.0", Some(35121)), @@ -1451,10 +1454,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } - ast::TyKind::ImplTrait(..) => { - gate_feature_post!(&self, conservative_impl_trait, ty.span, - "`impl Trait` is experimental"); - } ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental"); diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs deleted file mode 100644 index 0467c49b0311d..0000000000000 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 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(conservative_impl_trait)] - -fn arguments(_: impl Fn(), -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - _: Vec) {} -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - -type Factory = impl Fn() -> R; -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - -type GlobalFactory = fn() -> impl FnOnce() -> R; -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - -trait LazyToString { - fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String; - //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types -} - -impl LazyToString for String { - fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String { - //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - || self.clone() - } -} - -#[derive(Copy, Clone)] -struct Lazy(T); - -impl std::ops::Add> for Lazy { - type Output = impl Fn() -> Lazy; - //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - - fn add(self, other: Lazy) -> Self::Output { - move || Lazy(self.0 + other.0) - } -} - -impl std::ops::Add -for impl Fn() -> Lazy -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types -where F: Fn() -> impl FnOnce() -> i32 -//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types -{ - type Output = Self; - - fn add(self, other: F) -> Self::Output { - move || Lazy(self().0 + other()()) - } -} - -fn main() {} diff --git a/src/test/compile-fail/impl-trait/feature-gate-universal.rs b/src/test/compile-fail/impl-trait/feature-gate-universal.rs new file mode 100644 index 0000000000000..e5bdf3a42eb3e --- /dev/null +++ b/src/test/compile-fail/impl-trait/feature-gate-universal.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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. + +// gate-test-universal_impl_trait + +fn foo(x: impl std::fmt::Debug) { print!("{:?}", x); } +//~^ ERROR `impl Trait` in argument position is experimental + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/feature-gate.rs b/src/test/compile-fail/impl-trait/feature-gate.rs index f171b6becc4b7..d46a16450db52 100644 --- a/src/test/compile-fail/impl-trait/feature-gate.rs +++ b/src/test/compile-fail/impl-trait/feature-gate.rs @@ -11,6 +11,6 @@ // gate-test-conservative_impl_trait fn foo() -> impl Fn() { || {} } -//~^ ERROR `impl Trait` is experimental +//~^ ERROR `impl Trait` in return position is experimental fn main() {} diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs new file mode 100644 index 0000000000000..43b47e9e915f0 --- /dev/null +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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(universal_impl_trait)] +use std::fmt::Debug; + +trait Foo { + fn foo(&self, a: &A, b: &impl Debug); +} + +impl Foo for () { + fn foo(&self, a: &impl Debug, b: &B) { } + //~^ ERROR method `foo` has an incompatible type for trait +} + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs new file mode 100644 index 0000000000000..a95da61aa4c00 --- /dev/null +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs @@ -0,0 +1,32 @@ +// Copyright 2017 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(universal_impl_trait)] +use std::fmt::Debug; + +trait Foo { + fn foo(&self, _: &impl Debug); +} + +impl Foo for () { + fn foo(&self, _: &U) { } + //~^ Error method `foo` has incompatible signature for trait +} + +trait Bar { + fn bar(&self, _: &U); +} + +impl Bar for () { + fn bar(&self, _: &impl Debug) { } + //~^ Error method `bar` has incompatible signature for trait +} + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs new file mode 100644 index 0000000000000..af83a2d0a2337 --- /dev/null +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -0,0 +1,234 @@ +// Copyright 2017 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. + +//! A simple test for testing many permutations of allowedness of +//! impl Trait +#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)] +use std::fmt::Debug; + +// Allowed +fn in_parameters(_: impl Debug) { panic!() } + +// Allowed +fn in_return() -> impl Debug { panic!() } + +// Allowed +fn in_adt_in_parameters(_: Vec) { panic!() } + +// Allowed +fn in_adt_in_return() -> Vec { panic!() } + +// Disallowed +fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_Fn_parameter_in_generics (_: F) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + + +// Allowed +fn in_impl_Trait_in_parameters(_: impl Iterator) { panic!() } + +// Allowed +fn in_impl_Trait_in_return() -> impl IntoIterator { + vec![vec![0; 10], vec![12; 7], vec![8; 3]] +} + +// Disallowed +struct InBraceStructField { x: impl Debug } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +struct InAdtInBraceStructField { x: Vec } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +struct InTupleStructField(impl Debug); +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +enum InEnum { + InBraceVariant { x: impl Debug }, + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + InTupleVariant(impl Debug), + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Allowed +trait InTraitDefnParameters { + fn in_parameters(_: impl Debug); +} + +// Disallowed +trait InTraitDefnReturn { + fn in_return() -> impl Debug; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Allowed and disallowed in trait impls +trait DummyTrait { + type Out; + fn in_trait_impl_parameter(impl Debug); + fn in_trait_impl_return() -> Self::Out; +} +impl DummyTrait for () { + type Out = impl Debug; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + + fn in_trait_impl_parameter(_: impl Debug) { } + // Allowed + + fn in_trait_impl_return() -> impl Debug { () } + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Allowed +struct DummyType; +impl DummyType { + fn in_inherent_impl_parameters(_: impl Debug) { } + fn in_inherent_impl_return() -> impl Debug { () } +} + +// Disallowed +extern "C" { + fn in_foreign_parameters(_: impl Debug); + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + + fn in_foreign_return() -> impl Debug; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Allowed +extern "C" fn in_extern_fn_parameters(_: impl Debug) { +} + +// Allowed +extern "C" fn in_extern_fn_return() -> impl Debug { + 22 +} + +type InTypeAlias = impl Debug; +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +type InReturnInTypeAlias = fn() -> impl Debug; +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed in impl headers +impl PartialEq for () { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Disallowed in impl headers +impl PartialEq<()> for impl Debug { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Disallowed in inherent impls +impl impl Debug { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Disallowed in inherent impls +struct InInherentImplAdt { t: T } +impl InInherentImplAdt { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +// Disallowed in where clauses +fn in_fn_where_clause() + where impl Debug: Debug +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +{ +} + +// Disallowed in where clauses +fn in_adt_in_fn_where_clause() + where Vec: Debug +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +{ +} + +// Disallowed +fn in_trait_parameter_in_fn_where_clause() + where T: PartialEq +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +{ +} + +// Disallowed +fn in_Fn_parameter_in_fn_where_clause() + where T: Fn(impl Debug) +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +{ +} + +// Disallowed +fn in_Fn_return_in_fn_where_clause() + where T: Fn() -> impl Debug +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +{ +} + +fn main() { + let _in_local_variable: impl Fn() = || {}; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + let _in_return_in_local_variable = || -> impl Fn() { || {} }; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs index e9074f8c23096..e4f525a982610 100644 --- a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs +++ b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs @@ -10,9 +10,10 @@ #![feature(conservative_impl_trait)] -pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { - move |b| move |c| move |d| a + b + c + d -} +// NOTE commented out due to issue #45994 +//pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { +// move |b| move |c| move |d| a + b + c + d +//} fn some_internal_fn() -> u32 { 1 diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index 84d86cfdf65a4..0b612c2d3ff34 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, fn_traits, step_trait, unboxed_closures)] +#![feature(conservative_impl_trait, + universal_impl_trait, + fn_traits, + step_trait, + unboxed_closures +)] //! Derived from: . //! @@ -457,9 +462,9 @@ fn test_group_by() { /// /// Groups an iterator of dates by month. /// -fn by_month(it: It) - -> impl Iterator + Clone)> + Clone -where It: Iterator + Clone { +fn by_month(it: impl Iterator + Clone) + -> impl Iterator + Clone)> + Clone +{ it.group_by(|d| d.month()) } @@ -474,9 +479,9 @@ fn test_by_month() { /// /// Groups an iterator of dates by week. /// -fn by_week(it: It) - -> impl Iterator + Clone -where It: DateIterator { +fn by_week(it: impl DateIterator) + -> impl Iterator + Clone +{ // We go forward one day because `isoweekdate` considers the week to start on a Monday. it.group_by(|d| d.succ().isoweekdate().1) } @@ -548,8 +553,7 @@ const COLS_PER_WEEK: u32 = 7 * COLS_PER_DAY; /// /// Formats an iterator of weeks into an iterator of strings. /// -fn format_weeks(it: It) -> impl Iterator -where It: Iterator, It::Item: DateIterator { +fn format_weeks(it: impl Iterator) -> impl Iterator { it.map(|week| { let mut buf = String::with_capacity((COLS_PER_DAY * COLS_PER_WEEK + 2) as usize); @@ -627,7 +631,7 @@ fn test_month_title() { /// /// Formats a month. /// -fn format_month(it: It) -> impl Iterator { +fn format_month(it: impl DateIterator) -> impl Iterator { let mut month_days = it.peekable(); let title = month_title(month_days.peek().unwrap().month()); @@ -659,8 +663,9 @@ fn test_format_month() { /// /// Formats an iterator of months. /// -fn format_months(it: It) -> impl Iterator> -where It: Iterator, It::Item: DateIterator { +fn format_months(it: impl Iterator) + -> impl Iterator> +{ it.map(format_month) } diff --git a/src/test/compile-fail/impl-trait/disallowed-2.rs b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs similarity index 54% rename from src/test/compile-fail/impl-trait/disallowed-2.rs rename to src/test/run-pass/impl-trait/universal_hrtb_anon.rs index 46b3106ab8d6e..48874ef41de55 100644 --- a/src/test/compile-fail/impl-trait/disallowed-2.rs +++ b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] +#![feature(universal_impl_trait)] + +fn hrtb(f: impl Fn(&u32) -> u32) -> u32 { + f(&22) + f(&44) +} fn main() { - let _: impl Fn() = || {}; - //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - let _ = || -> impl Fn() { || {} }; - //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + let sum = hrtb(|x| x * 2); + assert_eq!(sum, 22*2 + 44*2); } diff --git a/src/test/run-pass/impl-trait/universal_hrtb_named.rs b/src/test/run-pass/impl-trait/universal_hrtb_named.rs new file mode 100644 index 0000000000000..95147a542005e --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_hrtb_named.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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(universal_impl_trait)] + +fn hrtb(f: impl for<'a> Fn(&'a u32) -> &'a u32) -> u32 { + f(&22) + f(&44) +} + +fn main() { + let sum = hrtb(|x| x); + assert_eq!(sum, 22 + 44); +} diff --git a/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs new file mode 100644 index 0000000000000..d0f18575297b2 --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs @@ -0,0 +1,31 @@ +// Copyright 2017 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(universal_impl_trait)] +use std::fmt::Display; + +fn check_display_eq(iter: &Vec) { + let mut collected = String::new(); + for it in iter { + let disp = format!("{} ", it); + collected.push_str(&disp); + } + assert_eq!("0 3 27 823 4891 1 0", collected.trim()); +} + +fn main() { + let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0]; + let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0]; + let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"]; + + check_display_eq(&i32_list_vec); + check_display_eq(&u32_list_vec); + check_display_eq(&str_list_vec); +} diff --git a/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs new file mode 100644 index 0000000000000..ccf24b77a6b77 --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs @@ -0,0 +1,39 @@ +// Copyright 2017 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(universal_impl_trait)] +use std::fmt::Display; + +fn check_display_eq(iter: impl IntoIterator) { + let mut collected = String::new(); + for it in iter { + let disp = format!("{} ", it); + collected.push_str(&disp); + } + assert_eq!("0 3 27 823 4891 1 0", collected.trim()); +} + +fn main() { + let i32_list = [0i32, 3, 27, 823, 4891, 1, 0]; + let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0]; + let u32_list = [0u32, 3, 27, 823, 4891, 1, 0]; + let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0]; + let u16_list = [0u16, 3, 27, 823, 4891, 1, 0]; + let str_list = ["0", "3", "27", "823", "4891", "1", "0"]; + let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"]; + + check_display_eq(&i32_list); + check_display_eq(i32_list_vec); + check_display_eq(&u32_list); + check_display_eq(u32_list_vec); + check_display_eq(&u16_list); + check_display_eq(&str_list); + check_display_eq(str_list_vec); +} diff --git a/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs new file mode 100644 index 0000000000000..af0201b5f871e --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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(universal_impl_trait)] + +use std::fmt::Debug; + +trait InTraitDefnParameters { + fn in_parameters(_: impl Debug) -> String; +} + +impl InTraitDefnParameters for () { + fn in_parameters(v: impl Debug) -> String { + format!("() + {:?}", v) + } +} + +fn main() { + let s = <() as InTraitDefnParameters>::in_parameters(22); + assert_eq!(s, "() + 22"); +} diff --git a/src/test/run-pass/impl-trait/universal_multiple_bounds.rs b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs new file mode 100644 index 0000000000000..bb332c0c96cb5 --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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(universal_impl_trait)] + +use std::fmt::Display; + +fn foo(f: impl Display + Clone) -> String { + let g = f.clone(); + format!("{} + {}", f, g) +} + +fn main() { + let sum = foo(format!("22")); + assert_eq!(sum, r"22 + 22"); +} diff --git a/src/test/run-pass/impl-trait/xcrate.rs b/src/test/run-pass/impl-trait/xcrate.rs index 6d00c46fa3508..35ae185b3e1de 100644 --- a/src/test/run-pass/impl-trait/xcrate.rs +++ b/src/test/run-pass/impl-trait/xcrate.rs @@ -13,6 +13,7 @@ extern crate xcrate; fn main() { - assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10); +// NOTE line below commeted out due to issue #45994 +// assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10); xcrate::return_closure_accessing_internal_fn()(); } diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs index 4670c5386c83c..554c71500cc8b 100644 --- a/src/test/rustdoc/issue-43869.rs +++ b/src/test/rustdoc/issue-43869.rs @@ -55,13 +55,15 @@ pub fn test_44731_1() -> Result, ()> { Ok(Box::new(j())) } -pub fn test_44731_2() -> Box { - Box::new(|_: u32| {}) -} - -pub fn test_44731_3() -> Box impl Clone> { - Box::new(|| 0u32) -} +// NOTE these involve Fn sugar, where impl Trait is disallowed for now, see issue #45994 +// +//pub fn test_44731_2() -> Box { +// Box::new(|_: u32| {}) +//} +// +//pub fn test_44731_3() -> Box impl Clone> { +// Box::new(|| 0u32) +//} pub fn test_44731_4() -> Box> { Box::new(g()) @@ -78,6 +80,4 @@ pub fn test_44731_4() -> Box> { // @has issue_43869/fn.o.html // @has issue_43869/fn.test_44731_0.html // @has issue_43869/fn.test_44731_1.html -// @has issue_43869/fn.test_44731_2.html -// @has issue_43869/fn.test_44731_3.html // @has issue_43869/fn.test_44731_4.html diff --git a/src/test/ui/impl-trait/universal-mismatched-type.rs b/src/test/ui/impl-trait/universal-mismatched-type.rs new file mode 100644 index 0000000000000..af7adc4c657d9 --- /dev/null +++ b/src/test/ui/impl-trait/universal-mismatched-type.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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(universal_impl_trait)] + +use std::fmt::Debug; + +fn foo(x: impl Debug) -> String { + x +} + +fn main() { } diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr new file mode 100644 index 0000000000000..2be2458449768 --- /dev/null +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/universal-mismatched-type.rs:16:5 + | +15 | fn foo(x: impl Debug) -> String { + | ------ expected `std::string::String` because of return type +16 | x + | ^ expected struct `std::string::String`, found type parameter + | + = note: expected type `std::string::String` + found type `impl Debug` + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.rs b/src/test/ui/impl-trait/universal-two-impl-traits.rs new file mode 100644 index 0000000000000..f8855a7975550 --- /dev/null +++ b/src/test/ui/impl-trait/universal-two-impl-traits.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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(universal_impl_trait)] + +use std::fmt::Debug; + +fn foo(x: impl Debug, y: impl Debug) -> String { + let mut a = x; + a = y; + format!("{:?}", a) +} + +fn main() { } diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr new file mode 100644 index 0000000000000..c663d38ca8a48 --- /dev/null +++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/universal-two-impl-traits.rs:17:9 + | +17 | a = y; + | ^ expected type parameter, found a different type parameter + | + = note: expected type `impl Debug` (type parameter) + found type `impl Debug` (type parameter) + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.rs b/src/test/ui/impl-trait/universal_wrong_bounds.rs new file mode 100644 index 0000000000000..fd35d04b25861 --- /dev/null +++ b/src/test/ui/impl-trait/universal_wrong_bounds.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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(universal_impl_trait)] + +use std::fmt::Display; + +fn foo(f: impl Display + Clone) -> String { + wants_debug(f); + wants_display(f); + wants_clone(f); +} + +fn wants_debug(g: impl Debug) { } +fn wants_display(g: impl Debug) { } +fn wants_cone(g: impl Clone) { } + +fn main() { +} diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr new file mode 100644 index 0000000000000..5e7788812e63c --- /dev/null +++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr @@ -0,0 +1,30 @@ +error[E0425]: cannot find function `wants_clone` in this scope + --> $DIR/universal_wrong_bounds.rs:18:5 + | +18 | wants_clone(f); + | ^^^^^^^^^^^ did you mean `wants_cone`? + +error[E0405]: cannot find trait `Debug` in this scope + --> $DIR/universal_wrong_bounds.rs:21:24 + | +21 | fn wants_debug(g: impl Debug) { } + | ^^^^^ not found in this scope + | +help: possible candidate is found in another module, you can import it into scope + | +13 | use std::fmt::Debug; + | + +error[E0405]: cannot find trait `Debug` in this scope + --> $DIR/universal_wrong_bounds.rs:22:26 + | +22 | fn wants_display(g: impl Debug) { } + | ^^^^^ not found in this scope + | +help: possible candidate is found in another module, you can import it into scope + | +13 | use std::fmt::Debug; + | + +error: cannot continue compilation due to previous error + diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr index 8a4dfdc80276a..08640b292eabc 100644 --- a/src/test/ui/resolve/use_suggestion_placement.stderr +++ b/src/test/ui/resolve/use_suggestion_placement.stderr @@ -33,17 +33,5 @@ help: possible candidates are found in other modules, you can import them into s 11 | use std::collections::hash_map::HashMap; | -error[E0091]: type parameter `K` is unused - --> $DIR/use_suggestion_placement.rs:35:15 - | -35 | type Dict = HashMap; - | ^ unused type parameter - -error[E0091]: type parameter `V` is unused - --> $DIR/use_suggestion_placement.rs:35:18 - | -35 | type Dict = HashMap; - | ^ unused type parameter - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml index 744a0f96ad734..f1684f4c5acbe 100644 --- a/src/tools/toolstate.toml +++ b/src/tools/toolstate.toml @@ -26,7 +26,7 @@ miri = "Broken" # ping @Manishearth @llogiq @mcarton @oli-obk -clippy = "Testing" +clippy = "Broken" # ping @nrc rls = "Testing"