From 779fc372c794057816951f2583985c512b0c6387 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:09:40 -0500 Subject: [PATCH 01/28] Move E0562 to librustc from librustc_typeck With the check for impl trait moving from type checking to HIR lowering the error needs to move too. --- src/librustc/diagnostics.rs | 40 ++++++++++++++++++++++++++++++ src/librustc_typeck/diagnostics.rs | 40 ------------------------------ 2 files changed, 40 insertions(+), 40 deletions(-) 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_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 73bec697d492e..cdf70847c02be 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. From 8fd48e7d59a01da7d631695cfea06027cb96c06a Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:23:59 -0500 Subject: [PATCH 02/28] Split hir::TyImplTrait, move checks to HIR lowering Replace hir::TyImplTrait with TyImplTraitUniversal and TyImplTraitExistential. Add an ImplTraitContext enum to rustc::hir::lowering to track the kind and allowedness of an impl Trait. Significantly alter lowering to thread ImplTraitContext and one other boolean parameter described below throughought much of lowering. The other parameter is for tracking if lowering a function is in a trait impl, as there is not enough information to otherwise know this information during lowering otherwise. This change also removes the checks from ast_ty_to_ty for impl trait allowedness as they are now all taking place in HIR lowering. --- src/librustc/hir/intravisit.rs | 5 +- src/librustc/hir/lowering.rs | 262 ++++++++++++++++-------- src/librustc/hir/mod.rs | 9 +- src/librustc/hir/print.rs | 3 +- src/librustc/ich/impls_hir.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc_metadata/encoder.rs | 2 +- src/librustc_privacy/lib.rs | 4 +- src/librustc_typeck/astconv.rs | 57 +----- src/librustc_typeck/collect.rs | 8 +- src/librustdoc/clean/mod.rs | 4 +- 11 files changed, 211 insertions(+), 148 deletions(-) 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..2fab130895c54 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -123,6 +123,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, @@ -644,48 +662,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 +717,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 +728,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 +745,21 @@ 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 => { + hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx)) + }, + ImplTraitContext::Universal(def_id) => { + 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 +805,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 +879,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 +915,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 +950,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 +972,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, itctx), ParenthesizedGenericArgs::Warn => { self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, CRATE_NODE_ID, data.span, msg.into()); @@ -960,7 +997,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,22 +1015,25 @@ 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) } fn lower_parenthesized_parameter_data(&mut self, - data: &ParenthesizedParameterData) + data: &ParenthesizedParameterData, + itctx: ImplTraitContext) -> (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 +1045,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, itctx)) .unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)), span: output.as_ref().map_or(span, |ty| ty.span), }], @@ -1018,7 +1058,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 +1095,24 @@ 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 { 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 (impl_trait_return_allow, fn_def_id) { + (false, _) => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), + (_, Some(_)) => 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 +1126,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 +1149,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 +1272,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 +1296,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 +1324,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 +1335,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 +1356,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 +1370,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 +1498,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 +1546,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 +1565,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 +1580,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 +1602,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 +1612,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 +1627,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 +1671,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 +1684,23 @@ 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 +1720,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 +1798,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), + let fn_def_id = this.resolver.definitions().opt_local_def_id(i.id); + hir::ForeignItemFn(this.lower_fn_decl(fdec, fn_def_id, true), 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 +1816,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 +1918,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 +2107,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 +2126,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 +2207,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 +2281,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 +2335,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..5d8e732b17c78 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -421,7 +421,8 @@ impl<'a> State<'a> { self.print_lifetime(lifetime)?; } } - hir::TyImplTrait(ref bounds) => { + hir::TyImplTraitExistential(ref bounds) | + hir::TyImplTraitUniversal(_, ref bounds) => { self.print_bounds("impl ", &bounds[..])?; } hir::TyArray(ref ty, v) => { 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..fc6f6ed9aa8a9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1698,7 +1698,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..34d617a205403 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::keywords; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::Span; @@ -1033,53 +1034,15 @@ 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, keywords::Invalid.name() /* FIXME(chrisvittal) invalid? */) } 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/collect.rs b/src/librustc_typeck/collect.rs index 814470974285f..69bdb68945d76 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -130,7 +130,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 +854,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) { @@ -1155,7 +1155,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) @@ -1373,7 +1373,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - 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); 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), } From e4c7e2c99a81179fe7d15e36c7f20724cf64ae7c Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:33:05 -0500 Subject: [PATCH 03/28] Add bool item is_in_impl_trait to LoweringContext This is for tracking if an ImplItem is part of a trait impl. Add a with_trait_impl_ref method to ItemLowerer to appropriately save the state to allow appropriate nesting of trait and non-trait impls. --- src/librustc/hir/lowering.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2fab130895c54..ec5ca5c89ac90 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, @@ -174,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) } @@ -241,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; @@ -253,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); + } } } From 94df3c5edfcd5ffb176286b1c060cfe4244a8f23 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:38:05 -0500 Subject: [PATCH 04/28] Alter type collection to collect impl Trait bounds In ast_generics extraction in generics_of and explicit_predicates_of, also collect inputs if there are any. Then use a Visitor to extract the necessary information from the TyImplTraitUniversal types before extending generics and predicates with the new information. --- src/librustc_typeck/collect.rs | 145 +++++++++++++++++++++++++++------ 1 file changed, 121 insertions(+), 24 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 69bdb68945d76..909855c1669f1 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}; @@ -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: keywords::Invalid.name() /* FIXME(chrisvittal) maybe make not Invalid */, + 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, @@ -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,18 +1397,18 @@ 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), } } @@ -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,48 @@ 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> { + 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() }; + opt_inputs.map(|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 { + 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() +} From f225fe43f14a8a3887aca558f20c7d7e990b591e Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:45:34 -0500 Subject: [PATCH 05/28] Add collection of impl Trait argument lifetimes --- src/librustc/middle/resolve_lifetime.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index fc6f6ed9aa8a9..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 From 109f2dd36b38d0642246ad50101bba21f5c0fba9 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:47:33 -0500 Subject: [PATCH 06/28] Add new error comparision to hide desugaring First some background: To the compiler, the following two signatures in the trait vs the impl are the same. ```rust trait Foo { fn foo(&self, &impl Debug); } impl Foo for () { fn foo(&self, x: &U) { ... } } ``` We do not want to allow this, and so we add a new error and check. The check just tests that all paramters 'syntheticness' match up. As during collection, the impl Trait parameters are transformed into anonymous synthetic generics. Furthermore, causes a check for unused type parameters to be skipped in check_bounds_are_used if there is already a TyError. Thus, an unused input will not trigger `type parameter unused` errors. Update the one test that checked for this error in the case of a TyError. --- src/librustc_typeck/check/compare_method.rs | 47 +++++++++++++++++++ src/librustc_typeck/check/mod.rs | 4 ++ src/librustc_typeck/diagnostics.rs | 16 +++++++ .../resolve/use_suggestion_placement.stderr | 14 +----- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2c44c40d83d49..04fa99540a177 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, + E0642, + "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/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index cdf70847c02be..039af900e245b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4625,6 +4625,22 @@ It is recommended that you look for a `new` function or equivalent in the crate's documentation. "##, +E0642: r##" +This error indicates that there is a mismatch between generic parameters and +impl Trait parameters in a trait Declaration versus it's impl. + +```compile_fail,E0642 +#![feature(conservative_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/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 From bdff9463a0afbbdcd52825ead6b6f9f1245652db Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 12:58:52 -0500 Subject: [PATCH 07/28] Add universal_impl_trait feature gate Move feature gate check to inside HIR lowering. Change error messages and update tests. --- src/librustc/hir/lowering.rs | 12 ++++++++++++ src/libsyntax/feature_gate.rs | 7 +++---- .../impl-trait/feature-gate-universal.rs | 16 ++++++++++++++++ src/test/compile-fail/impl-trait/feature-gate.rs | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/impl-trait/feature-gate-universal.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ec5ca5c89ac90..723f50faa8564 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -771,9 +771,21 @@ impl<'a> LoweringContext<'a> { 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 => { 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/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() {} From 06dff800614cab4e662ace032a2e61568db8bbdf Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 13:02:06 -0500 Subject: [PATCH 08/28] Add/Modify tests for argument position impl Trait --- .../compile-fail/impl-trait/disallowed.rs | 5 -- .../impl-trait/impl-generic-mismatch.rs | 32 +++++++++ .../compile-fail/impl-trait/many-cases.rs | 71 +++++++++++++++++++ .../run-pass/impl-trait/equality-universal.rs | 39 ++++++++++ .../run-pass/impl-trait/example-calendar.rs | 31 ++++---- src/test/rustdoc/issue-43869.rs | 4 -- 6 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 src/test/compile-fail/impl-trait/impl-generic-mismatch.rs create mode 100644 src/test/compile-fail/impl-trait/many-cases.rs create mode 100644 src/test/run-pass/impl-trait/equality-universal.rs diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs index 0467c49b0311d..bf2e22aa8e6f7 100644 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ b/src/test/compile-fail/impl-trait/disallowed.rs @@ -10,11 +10,6 @@ #![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 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..41583d3b795fc --- /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/many-cases.rs b/src/test/compile-fail/impl-trait/many-cases.rs new file mode 100644 index 0000000000000..5c2a8f89bf2e7 --- /dev/null +++ b/src/test/compile-fail/impl-trait/many-cases.rs @@ -0,0 +1,71 @@ +// 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 simple_universal(_: impl Debug) { panic!() } + +// Allowed +fn simple_existential() -> impl Debug { panic!() } + +// Allowed +fn collection_universal(_: Vec) { panic!() } + +// Allowed +fn collection_existential() -> Vec { panic!() } + +// Disallowed +fn fn_type_universal(_: fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +fn fn_type_existential() -> fn(impl Debug) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Allowed +fn dyn_universal(_: &dyn Iterator) { panic!() } + +// Disallowed +fn dyn_fn_trait(_: &dyn Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Allowed +fn nested_universal(_: impl Iterator) { panic!() } + +// Allowed +fn nested_existential() -> impl IntoIterator { + vec![vec![0; 10], vec![12; 7], vec![8; 3]] +} + +// Disallowed +fn universal_fn_trait(_: impl Fn(impl Debug)) { panic!() } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +struct ImplMember { x: impl Debug } +//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + +// Disallowed +trait Universal { + // FIXME, should error? + fn universal(impl Debug); +} + +// Disallowed +trait Existential { + fn existential() -> impl Debug; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +} + +fn main() {} diff --git a/src/test/run-pass/impl-trait/equality-universal.rs b/src/test/run-pass/impl-trait/equality-universal.rs new file mode 100644 index 0000000000000..ccf24b77a6b77 --- /dev/null +++ b/src/test/run-pass/impl-trait/equality-universal.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/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/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs index 4670c5386c83c..70a5a7a3f7a74 100644 --- a/src/test/rustdoc/issue-43869.rs +++ b/src/test/rustdoc/issue-43869.rs @@ -55,9 +55,6 @@ 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) @@ -78,6 +75,5 @@ 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 From a23bea5479d8fcd09b29673932bd736bac3db13d Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 14:18:10 -0500 Subject: [PATCH 09/28] Fix style and grammar --- src/librustc_typeck/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 039af900e245b..9711038a8f72b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4627,7 +4627,7 @@ crate's documentation. E0642: r##" This error indicates that there is a mismatch between generic parameters and -impl Trait parameters in a trait Declaration versus it's impl. +impl Trait parameters in a trait declaration versus its impl. ```compile_fail,E0642 #![feature(conservative_impl_trait)] From 7d25d2e05448663ac7294bc8d0bc6bdfe8f8c4c5 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 14:56:16 -0500 Subject: [PATCH 10/28] Remove unamed parameters --- src/librustc_typeck/diagnostics.rs | 4 ++-- src/test/compile-fail/impl-trait/impl-generic-mismatch.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 9711038a8f72b..413cc0ae83194 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4630,9 +4630,9 @@ This error indicates that there is a mismatch between generic parameters and impl Trait parameters in a trait declaration versus its impl. ```compile_fail,E0642 -#![feature(conservative_impl_trait)] +#![feature(universal_impl_trait)] trait Foo - fn foo(&self, &impl Iterator) + fn foo(&self, _: &impl Iterator) } impl Foo for () { fn foo(&self, _: &U) { } // error method `foo` has incompatible diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs index 41583d3b795fc..a95da61aa4c00 100644 --- a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs @@ -12,7 +12,7 @@ use std::fmt::Debug; trait Foo { - fn foo(&self, &impl Debug); + fn foo(&self, _: &impl Debug); } impl Foo for () { @@ -21,7 +21,7 @@ impl Foo for () { } trait Bar { - fn bar(&self, &U); + fn bar(&self, _: &U); } impl Bar for () { From 04ad8fd7a50ecd2c06556455cf25cc29fced1812 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 15:35:19 -0500 Subject: [PATCH 11/28] Fix unclosed delimiter in sample error --- src/librustc_typeck/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 413cc0ae83194..51ad668550e7d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4631,8 +4631,8 @@ impl Trait parameters in a trait declaration versus its impl. ```compile_fail,E0642 #![feature(universal_impl_trait)] -trait Foo - fn foo(&self, _: &impl Iterator) +trait Foo { + fn foo(&self, _: &impl Iterator); } impl Foo for () { fn foo(&self, _: &U) { } // error method `foo` has incompatible From b4c1aef1ca575e39481ea6c3295fc6b44f78f952 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Fri, 10 Nov 2017 15:51:28 -0500 Subject: [PATCH 12/28] Add universal_impl_trait unstable-book entry --- .../language-features/universal-impl-trait.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/universal-impl-trait.md 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))); +} +``` From 252027960410da9f425cab9b6f6599af1d63800f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 13:26:27 -0500 Subject: [PATCH 13/28] test we reject equivalent signatures with more than one argument --- .../impl-trait/impl-generic-mismatch-ab.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs 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() {} From ebc4408fc02c5847012a01e30f5ffcf4bc6bfea3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:05:31 -0500 Subject: [PATCH 14/28] rename many-cases to where-allowed --- .../compile-fail/impl-trait/{many-cases.rs => where-allowed.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/compile-fail/impl-trait/{many-cases.rs => where-allowed.rs} (100%) diff --git a/src/test/compile-fail/impl-trait/many-cases.rs b/src/test/compile-fail/impl-trait/where-allowed.rs similarity index 100% rename from src/test/compile-fail/impl-trait/many-cases.rs rename to src/test/compile-fail/impl-trait/where-allowed.rs From 37dd79ff44cf129e4639eec6b314d41269a9d145 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:07:00 -0500 Subject: [PATCH 15/28] extend `where-allowed.rs` with many more cases also merge disallowed and disallowed-2 into that set --- .../compile-fail/impl-trait/disallowed-2.rs | 18 -- .../compile-fail/impl-trait/disallowed.rs | 56 ----- .../compile-fail/impl-trait/where-allowed.rs | 198 ++++++++++++++++-- 3 files changed, 179 insertions(+), 93 deletions(-) delete mode 100644 src/test/compile-fail/impl-trait/disallowed-2.rs delete mode 100644 src/test/compile-fail/impl-trait/disallowed.rs diff --git a/src/test/compile-fail/impl-trait/disallowed-2.rs b/src/test/compile-fail/impl-trait/disallowed-2.rs deleted file mode 100644 index 46b3106ab8d6e..0000000000000 --- a/src/test/compile-fail/impl-trait/disallowed-2.rs +++ /dev/null @@ -1,18 +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 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 -} 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 bf2e22aa8e6f7..0000000000000 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ /dev/null @@ -1,56 +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)] - -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/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index 5c2a8f89bf2e7..be990b0e15d96 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -14,58 +14,218 @@ use std::fmt::Debug; // Allowed -fn simple_universal(_: impl Debug) { panic!() } +fn in_parameters(_: impl Debug) { panic!() } // Allowed -fn simple_existential() -> impl Debug { panic!() } +fn in_return() -> impl Debug { panic!() } // Allowed -fn collection_universal(_: Vec) { panic!() } +fn in_adt_in_parameters(_: Vec) { panic!() } // Allowed -fn collection_existential() -> Vec { panic!() } +fn in_adt_in_return() -> Vec { panic!() } // Disallowed -fn fn_type_universal(_: fn(impl Debug)) { panic!() } +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 fn_type_existential() -> fn(impl Debug) { panic!() } +fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types -// Allowed -fn dyn_universal(_: &dyn Iterator) { panic!() } +// 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 +// FIXME -- no error currently + +// 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 +// FIXME -- no error currently + +// 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 +// FIXME -- no error currently // Disallowed -fn dyn_fn_trait(_: &dyn Fn(impl Debug)) { panic!() } +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 +// FIXME -- no error currently + // Allowed -fn nested_universal(_: impl Iterator) { panic!() } +fn in_impl_Trait_in_parameters(_: impl Iterator) { panic!() } // Allowed -fn nested_existential() -> impl IntoIterator { +fn in_impl_Trait_in_return() -> impl IntoIterator { vec![vec![0; 10], vec![12; 7], vec![8; 3]] } // Disallowed -fn universal_fn_trait(_: impl Fn(impl Debug)) { panic!() } +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 ImplMember { x: impl Debug } +struct InTupleStructField(impl Debug); //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types // Disallowed -trait Universal { - // FIXME, should error? - fn universal(impl Debug); +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 Existential { - fn existential() -> impl Debug; +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 + // FIXME currently allowed + + fn in_foreign_return() -> impl Debug; + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types + // FIXME currently allowed +} + +// 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 } -fn main() {} From 6f9fb9103393fc5f5e11d4875c0c2a93b92bc714 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:11:10 -0500 Subject: [PATCH 16/28] rename `equality-universal` to a more extensible naming scheme --- ...lity-universal.rs => universal_in_impl_trait_in_parameters.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/run-pass/impl-trait/{equality-universal.rs => universal_in_impl_trait_in_parameters.rs} (100%) diff --git a/src/test/run-pass/impl-trait/equality-universal.rs b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs similarity index 100% rename from src/test/run-pass/impl-trait/equality-universal.rs rename to src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs From 9d71bf6d556e116e850c0d9b5f8975889b1ab575 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:16:34 -0500 Subject: [PATCH 17/28] add some more positive tests It'd be good to have a positive test for each case where it is allowed, I should think. --- .../impl-trait/universal_hrtb_anon.rs | 20 ++++++++++++ .../impl-trait/universal_hrtb_named.rs | 20 ++++++++++++ .../universal_in_adt_in_parameters.rs | 31 +++++++++++++++++++ .../universal_in_trait_defn_parameters.rs | 28 +++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/test/run-pass/impl-trait/universal_hrtb_anon.rs create mode 100644 src/test/run-pass/impl-trait/universal_hrtb_named.rs create mode 100644 src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs create mode 100644 src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs diff --git a/src/test/run-pass/impl-trait/universal_hrtb_anon.rs b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs new file mode 100644 index 0000000000000..48874ef41de55 --- /dev/null +++ b/src/test/run-pass/impl-trait/universal_hrtb_anon.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 Fn(&u32) -> u32) -> u32 { + f(&22) + f(&44) +} + +fn main() { + 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_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"); +} From 15001ee336f864679eca133e9055b68614d50643 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:20:56 -0500 Subject: [PATCH 18/28] add a UI test showing the current output from an impl trait type --- .../impl-trait/universal-mismatched-type.rs | 19 +++++++++++++++++++ .../universal-mismatched-type.stderr | 13 +++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/impl-trait/universal-mismatched-type.rs create mode 100644 src/test/ui/impl-trait/universal-mismatched-type.stderr 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..7f206846ad17c --- /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 `` + +error: aborting due to previous error + From 2786ea662d338f92130f6965cbf38114a49f577c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Nov 2017 14:27:58 -0500 Subject: [PATCH 19/28] some tests featuring multiple bounds, other errors --- .../impl-trait/universal_multiple_bounds.rs | 23 ++++++++++++++++ .../ui/impl-trait/universal_wrong_bounds.rs | 26 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/run-pass/impl-trait/universal_multiple_bounds.rs create mode 100644 src/test/ui/impl-trait/universal_wrong_bounds.rs 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/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() { +} From 7e9948f92f5972e9b87b6f08dab51a7073b8a495 Mon Sep 17 00:00:00 2001 From: Chris Vittal Date: Tue, 14 Nov 2017 12:27:55 -0500 Subject: [PATCH 20/28] Add proper names to impl Trait parameters. Uses Symbol::intern and hir.node_to_pretty_string to create a name for the impl Trait parameter that is just impl and then a ' + ' separated list of bounds that the user typed. --- src/librustc/hir/print.rs | 2 +- src/librustc_typeck/astconv.rs | 5 +++-- src/librustc_typeck/collect.rs | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5d8e732b17c78..451e870f500dd 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -423,7 +423,7 @@ impl<'a> State<'a> { } hir::TyImplTraitExistential(ref bounds) | hir::TyImplTraitUniversal(_, ref bounds) => { - self.print_bounds("impl ", &bounds[..])?; + self.print_bounds("impl", &bounds[..])?; } hir::TyArray(ref ty, v) => { self.s.word("[")?; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 34d617a205403..7aaf65e1fd07d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -30,7 +30,7 @@ use util::nodemap::FxHashSet; use std::iter; use syntax::{abi, ast}; -use syntax::symbol::keywords; +use syntax::symbol::Symbol; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::Span; @@ -1042,7 +1042,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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, keywords::Invalid.name() /* FIXME(chrisvittal) invalid? */) + 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/collect.rs b/src/librustc_typeck/collect.rs index 909855c1669f1..76afd4e2bd1d8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1001,7 +1001,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .chain(univ_impl_trait_info.iter().enumerate().map(|(i, info)| { ty::TypeParameterDef { index: other_type_start + i as u32, - name: keywords::Invalid.name() /* FIXME(chrisvittal) maybe make not Invalid */, + 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, @@ -1732,6 +1732,7 @@ fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } struct ImplTraitUniversalInfo<'hir> { + id: ast::NodeId, def_id: DefId, span: Span, bounds: &'hir [hir::TyParamBound], @@ -1767,6 +1768,7 @@ fn extract_universal_impl_trait_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); 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 From 9b4372e3b1a4a25972e524687ba1c719bcaf243a Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 16:24:35 -0500 Subject: [PATCH 21/28] Incorporate review feedback Add requested comments, restructure some small bits of code. Fix extern declarations allowing impl Trait. --- src/librustc/hir/lowering.rs | 21 +++++++++++++------ src/librustc_typeck/collect.rs | 10 ++++++--- .../compile-fail/impl-trait/where-allowed.rs | 2 -- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 723f50faa8564..e47b15e3781fb 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1130,11 +1130,19 @@ impl<'a> LoweringContext<'a> { }).collect() } + 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| if let Some(def_id) = fn_def_id { @@ -1143,9 +1151,9 @@ impl<'a> LoweringContext<'a> { self.lower_ty(&arg.ty, ImplTraitContext::Disallowed) }).collect(), output: match decl.output { - FunctionRetTy::Ty(ref ty) => match (impl_trait_return_allow, fn_def_id) { - (false, _) => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), - (_, Some(_)) => hir::Return(self.lower_ty(ty, ImplTraitContext::Existential)), + 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), @@ -1730,7 +1738,8 @@ impl<'a> LoweringContext<'a> { this.expr_block(body, ThinVec::new()) }); let impl_trait_return_allow = !this.is_in_trait_impl; - hir::ImplItemKind::Method(this.lower_method_sig(sig, fn_def_id, + hir::ImplItemKind::Method(this.lower_method_sig(sig, + fn_def_id, impl_trait_return_allow), body_id) } @@ -1833,8 +1842,8 @@ impl<'a> LoweringContext<'a> { attrs: this.lower_attrs(&i.attrs), node: match i.node { ForeignItemKind::Fn(ref fdec, ref generics) => { - let fn_def_id = this.resolver.definitions().opt_local_def_id(i.id); - hir::ForeignItemFn(this.lower_fn_decl(fdec, fn_def_id, true), + // 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)) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 76afd4e2bd1d8..b5fbbeb1692e6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1763,9 +1763,13 @@ fn extract_universal_impl_trait_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let mut visitor = ImplTraitUniversalVisitor { items: Vec::new() }; - opt_inputs.map(|inputs| for t in inputs.iter() { - visitor.visit_ty(t); - }); + + 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, diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index be990b0e15d96..a4361446020b0 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -144,11 +144,9 @@ impl DummyType { extern "C" { fn in_foreign_parameters(_: impl Debug); //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - // FIXME currently allowed fn in_foreign_return() -> impl Debug; //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types - // FIXME currently allowed } // Allowed From b27642973421c6c4e588b4a2d12c7120c4c21176 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 19:57:09 -0500 Subject: [PATCH 22/28] Disallow all impl Trait within Fn trait sugar We already disallowed them to be in the arg list, such as Fn(impl Debug), but now we disallow Fn() -> impl Debug. Also remove the ImplTraitContext argument from the function lower_parenthesized_parameter_data as it is now unused. Comment out part of test run-pass/impl-trait/xcrate.rs that now fails. --- src/librustc/hir/lowering.rs | 7 +++---- src/test/run-pass/impl-trait/auxiliary/xcrate.rs | 7 ++++--- src/test/run-pass/impl-trait/xcrate.rs | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e47b15e3781fb..8c9d1a38e7088 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1018,7 +1018,7 @@ impl<'a> LoweringContext<'a> { } PathParameters::Parenthesized(ref data) => match parenthesized_generic_args { ParenthesizedGenericArgs::Ok => - self.lower_parenthesized_parameter_data(data, itctx), + 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()); @@ -1063,8 +1063,7 @@ impl<'a> LoweringContext<'a> { } fn lower_parenthesized_parameter_data(&mut self, - data: &ParenthesizedParameterData, - itctx: ImplTraitContext) + data: &ParenthesizedParameterData) -> (hir::PathParameters, bool) { const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed; let &ParenthesizedParameterData { ref inputs, ref output, span } = data; @@ -1080,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, itctx)) + 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), }], 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/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()(); } From f710d41f77853279832880cc9b3e01ea141daac9 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 20:07:53 -0500 Subject: [PATCH 23/28] Add/Fix stderr references for impl Trait ui tests --- .../universal-mismatched-type.stderr | 2 +- .../impl-trait/universal_wrong_bounds.stderr | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/impl-trait/universal_wrong_bounds.stderr diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index 7f206846ad17c..2be2458449768 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types | ^ expected struct `std::string::String`, found type parameter | = note: expected type `std::string::String` - found type `` + found type `impl Debug` error: aborting due to previous error 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 + From 22f0940f2d7076773966de425f5dfc3afb012164 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 20:38:07 -0500 Subject: [PATCH 24/28] Add cases to where-allowed.rs --- src/test/compile-fail/impl-trait/where-allowed.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index a4361446020b0..af83a2d0a2337 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -48,7 +48,6 @@ fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } // 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 -// FIXME -- no error currently // Disallowed fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } @@ -57,7 +56,6 @@ fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } // 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 -// FIXME -- no error currently // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } @@ -66,7 +64,6 @@ fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } // 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 -// FIXME -- no error currently // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } @@ -75,7 +72,15 @@ fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } // 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 -// FIXME -- no error currently + +// 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!() } From 517db79c1f0c7d68f67045b19e19cbb369d2b7b8 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 20:56:42 -0500 Subject: [PATCH 25/28] Renumber error to fix tidy --- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/diagnostics.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 04fa99540a177..139449e5ab0ae 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -739,7 +739,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_span = tcx.hir.span(trait_node_id); let mut err = struct_span_err!(tcx.sess, impl_span, - E0642, + E0643, "method `{}` has incompatible signature for trait", trait_m.name); err.span_label(trait_span, "annotation in trait"); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 51ad668550e7d..328b7f9fdefca 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4625,11 +4625,11 @@ It is recommended that you look for a `new` function or equivalent in the crate's documentation. "##, -E0642: r##" +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,E0642 +```compile_fail,E0643 #![feature(universal_impl_trait)] trait Foo { fn foo(&self, _: &impl Iterator); From 337dee4c80d5c399981597defdf157e007f20a92 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Tue, 14 Nov 2017 21:24:43 -0500 Subject: [PATCH 26/28] Remove Fn trait + impl Trait rustdoc tests --- src/test/rustdoc/issue-43869.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs index 70a5a7a3f7a74..554c71500cc8b 100644 --- a/src/test/rustdoc/issue-43869.rs +++ b/src/test/rustdoc/issue-43869.rs @@ -55,10 +55,15 @@ pub fn test_44731_1() -> Result, ()> { Ok(Box::new(j())) } - -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()) @@ -75,5 +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_3.html // @has issue_43869/fn.test_44731_4.html From 98d5db3350c79f9f8061afc2e78fed838a45cfe5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 15 Nov 2017 13:28:35 -0500 Subject: [PATCH 27/28] add a new test featuring two impl traits to show what it looks like --- .../impl-trait/universal-two-impl-traits.rs | 21 +++++++++++++++++++ .../universal-two-impl-traits.stderr | 11 ++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/impl-trait/universal-two-impl-traits.rs create mode 100644 src/test/ui/impl-trait/universal-two-impl-traits.stderr 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 + From 4ce61b73620ade330bbafc3c6d56a0447bac2ca3 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Wed, 15 Nov 2017 15:38:54 -0500 Subject: [PATCH 28/28] Change clippy to broken after hir::Ty enum change --- src/tools/toolstate.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"