From ecda3356a41fff9e920e3894b94c29fb7966c7cc Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Fri, 21 Jun 2019 12:23:05 +0900 Subject: [PATCH 1/9] Support `impl Trait` in inlined documentation --- src/librustdoc/clean/inline.rs | 9 +- src/librustdoc/clean/mod.rs | 91 +++++++++++++++---- src/librustdoc/core.rs | 24 ++++- .../inline_cross/auxiliary/impl_trait_aux.rs | 7 ++ src/test/rustdoc/inline_cross/impl_trait.rs | 19 ++++ 5 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs create mode 100644 src/test/rustdoc/inline_cross/impl_trait.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9259b3b5d3abb..b023369bfe9dc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -210,8 +210,9 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { }; let predicates = cx.tcx.predicates_of(did); - let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); - let decl = (did, sig).clean(cx); + let (generics, decl) = clean::enter_impl_trait(cx, || { + ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) + }); let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { decl, @@ -347,7 +348,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { None } }).collect::>(), - (tcx.generics_of(did), &predicates).clean(cx), + clean::enter_impl_trait(cx, || { + (tcx.generics_of(did), &predicates).clean(cx) + }), ) }; let polarity = tcx.impl_polarity(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 41a56756a1480..b5fcecf39413e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -47,7 +47,7 @@ use std::u32; use parking_lot::ReentrantMutex; -use crate::core::{self, DocContext}; +use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; use crate::visit_ast; use crate::html::render::{cache, ExternalLocation}; @@ -1536,7 +1536,7 @@ impl Clean for ty::GenericParamDef { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } - ty::GenericParamDefKind::Type { has_default, .. } => { + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { cx.renderinfo.borrow_mut().external_param_names .insert(self.def_id, self.name.clean(cx)); let default = if has_default { @@ -1548,7 +1548,7 @@ impl Clean for ty::GenericParamDef { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. default, - synthetic: None, + synthetic, }) } ty::GenericParamDefKind::Const { .. } => { @@ -1637,7 +1637,7 @@ impl Clean for hir::Generics { match param.kind { GenericParamDefKind::Lifetime => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone()); + cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -1692,25 +1692,76 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, let (gens, preds) = *self; + // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, + // since `Clean for ty::Predicate` would consume them. + let mut impl_trait = FxHashMap::>::default(); + // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { .. } => { - if param.name.as_symbol() == kw::SelfUpper { - assert_eq!(param.index, 0); - return None; + let stripped_typarams = gens.params.iter().enumerate() + .filter_map(|(i, param)| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { synthetic, .. } => { + if param.name.as_symbol() == kw::SelfUpper { + assert_eq!(param.index, 0); + return None; + } + if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + impl_trait.insert((i as u32).into(), vec![]); + return None; + } + Some(param.clean(cx)) } - Some(param.clean(cx)) - } - ty::GenericParamDefKind::Const { .. } => None, - }).collect::>(); + ty::GenericParamDefKind::Const { .. } => None, + }).collect::>(); let mut where_predicates = preds.predicates.iter() - .flat_map(|(p, _)| p.clean(cx)) + .flat_map(|(p, _)| { + let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().sty { + Some(param.index) + } else { + None + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.sty { + Some(param.index) + } else { + None + } + } else { + None + }; + + let p = p.clean(cx)?; + + if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) { + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + return None; + } + + Some(p) + }) .collect::>(); + // Move `TraitPredicate`s to the front. + for (_, bounds) in impl_trait.iter_mut() { + bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { + false + } else { + true + }); + } + + cx.impl_trait_bounds.borrow_mut().extend(impl_trait); + // Type parameters and have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. @@ -2789,7 +2840,7 @@ impl Clean for hir::Ty { if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { return new_ty; } - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) { return ImplTrait(bounds); } } @@ -3079,7 +3130,13 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Projection(ref data) => data.clean(cx), - ty::Param(ref p) => Generic(p.name.to_string()), + ty::Param(ref p) => { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { + ImplTrait(bounds) + } else { + Generic(p.name.to_string()) + } + } ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7da501ef6cb74..ec834c373da4f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -65,8 +65,8 @@ pub struct DocContext<'tcx> { pub lt_substs: RefCell>, /// Table `DefId` of const parameter -> substituted const pub ct_substs: RefCell>, - /// Table DefId of `impl Trait` in argument position -> bounds - pub impl_trait_bounds: RefCell>>, + /// Table synthetic type parameter for `impl Trait` in argument position -> bounds + pub impl_trait_bounds: RefCell>>, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. @@ -472,3 +472,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) }) } + +/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter +/// for `impl Trait` in argument position. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum ImplTraitParam { + DefId(DefId), + ParamIndex(u32), +} + +impl From for ImplTraitParam { + fn from(did: DefId) -> Self { + ImplTraitParam::DefId(did) + } +} + +impl From for ImplTraitParam { + fn from(idx: u32) -> Self { + ImplTraitParam::ParamIndex(idx) + } +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs new file mode 100644 index 0000000000000..7807acbc4d61d --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -0,0 +1,7 @@ +pub fn func<'a>(_x: impl Clone + Into> + 'a) {} + +pub struct Foo; + +impl Foo { + pub fn method<'a>(_x: impl Clone + Into> + 'a) {} +} diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs new file mode 100644 index 0000000000000..02c49145c762e --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,19 @@ +// aux-build:impl_trait_aux.rs + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' '(_x: impl ' +// @has - '//pre[@class="rust fn"]' 'Clone' +// @has - '//pre[@class="rust fn"]' 'Into' +// @has - '//pre[@class="rust fn"]' "'a" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/struct.Foo.html +// @has - '//code[@id="method.v"]' '(_x: impl ' +// @has - '//code[@id="method.v"]' 'Clone' +// @has - '//code[@id="method.v"]' 'Into' +// @has - '//code[@id="method.v"]' "'a" +// @!has - '//code[@id="method.v"]' 'where' +pub use impl_trait_aux::Foo; From de8660ab610f046bbdeb1a90f2c94cba1d3d3185 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 24 Jun 2019 09:15:07 +0100 Subject: [PATCH 2/9] typeck: merge opaque type inference logic This commit merges the logic used for opaque type type inference for impl Trait and non-impl Trait cases. This fixes an ICE where existential types used in the return types of functions would be allowed to have an out-of-scope generic type parameter. --- src/librustc/infer/opaque_types/mod.rs | 76 +++++++++- src/librustc_typeck/check/writeback.rs | 153 ++------------------ src/test/ui/impl-trait/issue-55872-1.rs | 22 +++ src/test/ui/impl-trait/issue-55872-1.stderr | 33 +++++ src/test/ui/impl-trait/issue-55872-2.rs | 20 +++ src/test/ui/impl-trait/issue-55872-2.stderr | 21 +++ src/test/ui/impl-trait/issue-55872.rs | 19 +++ src/test/ui/impl-trait/issue-55872.stderr | 12 ++ 8 files changed, 217 insertions(+), 139 deletions(-) create mode 100644 src/test/ui/impl-trait/issue-55872-1.rs create mode 100644 src/test/ui/impl-trait/issue-55872-1.stderr create mode 100644 src/test/ui/impl-trait/issue-55872-2.rs create mode 100644 src/test/ui/impl-trait/issue-55872-2.stderr create mode 100644 src/test/ui/impl-trait/issue-55872.rs create mode 100644 src/test/ui/impl-trait/issue-55872.stderr diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index f43e3fa0b7787..9c105b6b891f9 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -4,6 +4,7 @@ use crate::hir::Node; use crate::infer::outlives::free_region_map::FreeRegionRelations; use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; use crate::middle::region; +use crate::mir::interpret::ConstValue; use crate::traits::{self, PredicateObligation}; use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind}; @@ -553,6 +554,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { def_id: DefId, opaque_defn: &OpaqueTypeDecl<'tcx>, instantiated_ty: Ty<'tcx>, + span: Span, ) -> Ty<'tcx> { debug!( "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", @@ -584,6 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { def_id, map, instantiated_ty, + span, )); debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty); @@ -761,6 +764,9 @@ struct ReverseMapper<'tcx> { /// initially `Some`, set to `None` once error has been reported hidden_ty: Option>, + + /// Span of function being checked. + span: Span, } impl ReverseMapper<'tcx> { @@ -770,6 +776,7 @@ impl ReverseMapper<'tcx> { opaque_type_def_id: DefId, map: FxHashMap, Kind<'tcx>>, hidden_ty: Ty<'tcx>, + span: Span, ) -> Self { Self { tcx, @@ -778,6 +785,7 @@ impl ReverseMapper<'tcx> { map, map_missing_regions_to_empty: false, hidden_ty: Some(hidden_ty), + span, } } @@ -812,10 +820,11 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { _ => { } } + let generics = self.tcx().generics_of(self.opaque_type_def_id); match self.map.get(&r.into()).map(|k| k.unpack()) { Some(UnpackedKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None => { + None if generics.parent.is_some() => { if !self.map_missing_regions_to_empty && !self.tainted_by_errors { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( @@ -829,6 +838,21 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { } self.tcx.lifetimes.re_empty } + None => { + self.tcx.sess + .struct_span_err( + self.span, + "non-defining existential type use in defining scope" + ) + .span_label( + self.span, + format!("lifetime `{}` is part of concrete type but not used in \ + parameter list of existential type", r), + ) + .emit(); + + self.tcx().global_tcx().mk_region(ty::ReStatic) + }, } } @@ -890,9 +914,59 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability) } + ty::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ty.into()).map(|k| k.unpack()) { + // Found it in the substitution list; replace with the parameter from the + // existential type. + Some(UnpackedKind::Type(t1)) => t1, + Some(u) => panic!("type mapped to unexpected kind: {:?}", u), + None => { + self.tcx.sess + .struct_span_err( + self.span, + &format!("type parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", ty), + ) + .emit(); + + self.tcx().types.err + } + } + } + _ => ty.super_fold_with(self), } } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + trace!("checking const {:?}", ct); + // Find a const parameter + match ct.val { + ConstValue::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ct.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // existential type. + Some(UnpackedKind::Const(c1)) => c1, + Some(u) => panic!("const mapped to unexpected kind: {:?}", u), + None => { + self.tcx.sess + .struct_span_err( + self.span, + &format!("const parameter `{}` is part of concrete type but not \ + used in parameter list for existential type", ct) + ) + .emit(); + + self.tcx().consts.err + } + } + } + + _ => ct, + } + } } struct Instantiator<'a, 'tcx> { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 28711e32a4c51..2a33b47c93a61 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -9,10 +9,8 @@ use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; -use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; -use rustc::ty::subst::UnpackedKind; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; use std::mem; @@ -440,141 +438,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { debug_assert!(!instantiated_ty.has_escaping_bound_vars()); - let generics = self.tcx().generics_of(def_id); - - let definition_ty = if generics.parent.is_some() { - // `impl Trait` - self.fcx.infer_opaque_definition_from_instantiation( - def_id, - opaque_defn, - instantiated_ty, - ) - } else { - // Prevent: - // * `fn foo() -> Foo` - // * `fn foo() -> Foo` - // from being defining. - - // Also replace all generic params with the ones from the existential type - // definition so that - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. } - // ``` - // figures out the concrete type with `U`, but the stored type is with `T`. - instantiated_ty.fold_with(&mut BottomUpFolder { - tcx: self.tcx().global_tcx(), - ty_op: |ty| { - trace!("checking type {:?}", ty); - // Find a type parameter. - if let ty::Param(..) = ty.sty { - // Look it up in the substitution list. - assert_eq!(opaque_defn.substs.len(), generics.params.len()); - for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) { - if let UnpackedKind::Type(subst) = subst.unpack() { - if subst == ty { - // Found it in the substitution list; replace with the - // parameter from the existential type. - return self.tcx() - .global_tcx() - .mk_ty_param(param.index, param.name); - } - } - } - self.tcx() - .sess - .struct_span_err( - span, - &format!( - "type parameter `{}` is part of concrete type but not used \ - in parameter list for existential type", - ty, - ), - ) - .emit(); - return self.tcx().types.err; - } - ty - }, - lt_op: |region| { - match region { - // Skip static and bound regions: they don't require substitution. - ty::ReStatic | ty::ReLateBound(..) => region, - _ => { - trace!("checking {:?}", region); - for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) { - if let UnpackedKind::Lifetime(subst) = subst.unpack() { - if subst == region { - // Found it in the substitution list; replace with the - // parameter from the existential type. - let reg = ty::EarlyBoundRegion { - def_id: p.def_id, - index: p.index, - name: p.name, - }; - trace!("replace {:?} with {:?}", region, reg); - return self.tcx() - .global_tcx() - .mk_region(ty::ReEarlyBound(reg)); - } - } - } - trace!("opaque_defn: {:#?}", opaque_defn); - trace!("generics: {:#?}", generics); - self.tcx() - .sess - .struct_span_err( - span, - "non-defining existential type use in defining scope", - ) - .span_label( - span, - format!( - "lifetime `{}` is part of concrete type but not used \ - in parameter list of existential type", - region, - ), - ) - .emit(); - self.tcx().global_tcx().mk_region(ty::ReStatic) - } - } - }, - ct_op: |ct| { - trace!("checking const {:?}", ct); - // Find a const parameter - if let ConstValue::Param(..) = ct.val { - // look it up in the substitution list - assert_eq!(opaque_defn.substs.len(), generics.params.len()); - for (subst, param) in opaque_defn.substs.iter() - .zip(&generics.params) { - if let UnpackedKind::Const(subst) = subst.unpack() { - if subst == ct { - // found it in the substitution list, replace with the - // parameter from the existential type - return self.tcx() - .global_tcx() - .mk_const_param(param.index, param.name, ct.ty); - } - } - } - self.tcx() - .sess - .struct_span_err( - span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for existential type", - ct, - ), - ) - .emit(); - return self.tcx().consts.err; - } - ct - } - }) - }; + // Prevent: + // * `fn foo() -> Foo` + // * `fn foo() -> Foo` + // from being defining. + + // Also replace all generic params with the ones from the existential type + // definition so that + // ```rust + // existential type Foo: 'static; + // fn foo() -> Foo { .. } + // ``` + // figures out the concrete type with `U`, but the stored type is with `T`. + let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( + def_id, opaque_defn, instantiated_ty, span); if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty { if def_id == defin_ty_def_id { diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs new file mode 100644 index 0000000000000..5095b26f8a4e0 --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -0,0 +1,22 @@ +// ignore-tidy-linelength +#![feature(existential_type)] + +pub trait Bar +{ + type E: Copy; + + fn foo() -> Self::E; +} + +impl Bar for S { + existential type E: Copy; + //~^ ERROR the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` [E0277] + //~^^ ERROR the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` [E0277] + + fn foo() -> Self::E { + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type + (S::default(), T::default()) + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr new file mode 100644 index 0000000000000..04b4d2d4a50a5 --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:12:5 + | +LL | existential type E: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` + | + = help: consider adding a `where S: std::marker::Copy` bound + = note: required because it appears within the type `(S, T)` + = note: the return type of a function must have a statically known size + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:12:5 + | +LL | existential type E: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + = note: required because it appears within the type `(S, T)` + = note: the return type of a function must have a statically known size + +error: type parameter `T` is part of concrete type but not used in parameter list for existential type + --> $DIR/issue-55872-1.rs:16:37 + | +LL | fn foo() -> Self::E { + | _____________________________________^ +LL | | +LL | | (S::default(), T::default()) +LL | | } + | |_____^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs new file mode 100644 index 0000000000000..2bdeb14bdc3e6 --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -0,0 +1,20 @@ +// edition:2018 +// ignore-tidy-linelength +#![feature(async_await, existential_type)] + +pub trait Bar { + type E: Copy; + + fn foo() -> Self::E; +} + +impl Bar for S { + existential type E: Copy; + //~^ ERROR the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied [E0277] + fn foo() -> Self::E { + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type + async {} + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr new file mode 100644 index 0000000000000..2505a82ee23cb --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied + --> $DIR/issue-55872-2.rs:12:5 + | +LL | existential type E: Copy; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future` + | + = note: the return type of a function must have a statically known size + +error: type parameter `T` is part of concrete type but not used in parameter list for existential type + --> $DIR/issue-55872-2.rs:14:28 + | +LL | fn foo() -> Self::E { + | ____________________________^ +LL | | +LL | | async {} +LL | | } + | |_____^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs new file mode 100644 index 0000000000000..95604545c37f1 --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872.rs @@ -0,0 +1,19 @@ +// ignore-tidy-linelength +#![feature(existential_type)] + +pub trait Bar { + type E: Copy; + + fn foo() -> Self::E; +} + +impl Bar for S { + existential type E: Copy; + + fn foo() -> Self::E { + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for existential type + || () + } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr new file mode 100644 index 0000000000000..487f276e317e9 --- /dev/null +++ b/src/test/ui/impl-trait/issue-55872.stderr @@ -0,0 +1,12 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for existential type + --> $DIR/issue-55872.rs:13:28 + | +LL | fn foo() -> Self::E { + | ____________________________^ +LL | | +LL | | || () +LL | | } + | |_____^ + +error: aborting due to previous error + From e808d921ddc0ad81a200934fc4caabc34094afe5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 5 Jul 2019 11:38:40 +0200 Subject: [PATCH 3/9] Replace SliceConcatExt trait with inherent methods and SliceConcat helper trait Before this change `SliceConcatExt` was an unstable extension trait with stable methods. It was in the libstd prelude, so that its methods could be used on the stable channel. This replaces it with inherent methods, which can be used without any addition to the prelude. Since the methods are stable and very generic (with for example a return type that depends on the types of parameters), an helper trait is still needed. But now that trait does not need to be in scope for the methods to be used. Removing this depedency on the libstd prelude allows the methods to be used in `#![no_std]` crate that use liballoc, which does not have its own implicitly-imported prelude. --- src/liballoc/prelude/v1.rs | 1 - src/liballoc/slice.rs | 129 ++++++++++++++++++++----------------- src/liballoc/str.rs | 14 ++-- src/libstd/prelude/mod.rs | 3 - src/libstd/prelude/v1.rs | 3 - 5 files changed, 76 insertions(+), 74 deletions(-) diff --git a/src/liballoc/prelude/v1.rs b/src/liballoc/prelude/v1.rs index b6b01395ad632..3cb285bf0492f 100644 --- a/src/liballoc/prelude/v1.rs +++ b/src/liballoc/prelude/v1.rs @@ -6,6 +6,5 @@ #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::borrow::ToOwned; #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::boxed::Box; -#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::slice::SliceConcatExt; #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::string::{String, ToString}; #[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::vec::Vec; diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index f7b0a5e703cc3..bc4ae16798478 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -484,6 +484,56 @@ impl [T] { } buf } + + /// Flattens a slice of `T` into a single value `Self::Output`. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(["hello", "world"].concat(), "helloworld"); + /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn concat(&self) -> T::Output + where T: SliceConcat + { + SliceConcat::concat(self) + } + + /// Flattens a slice of `T` into a single value `Self::Output`, placing a + /// given separator between each. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(["hello", "world"].join(" "), "hello world"); + /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); + /// ``` + #[stable(feature = "rename_connect_to_join", since = "1.3.0")] + pub fn join(&self, sep: &Separator) -> T::Output + where T: SliceConcat + { + SliceConcat::join(self, sep) + } + + /// Flattens a slice of `T` into a single value `Self::Output`, placing a + /// given separator between each. + /// + /// # Examples + /// + /// ``` + /// # #![allow(deprecated)] + /// assert_eq!(["hello", "world"].connect(" "), "hello world"); + /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] + pub fn connect(&self, sep: &Separator) -> T::Output + where T: SliceConcat + { + SliceConcat::join(self, sep) + } + } #[lang = "slice_u8_alloc"] @@ -527,87 +577,46 @@ impl [u8] { //////////////////////////////////////////////////////////////////////////////// // Extension traits for slices over specific kinds of data //////////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "slice_concat_ext", - reason = "trait should not have to exist", - issue = "27747")] -/// An extension trait for concatenating slices -/// -/// While this trait is unstable, the methods are stable. `SliceConcatExt` is -/// included in the [standard library prelude], so you can use [`join()`] and -/// [`concat()`] as if they existed on `[T]` itself. -/// -/// [standard library prelude]: ../../std/prelude/index.html -/// [`join()`]: #tymethod.join -/// [`concat()`]: #tymethod.concat -pub trait SliceConcatExt { - #[unstable(feature = "slice_concat_ext", - reason = "trait should not have to exist", - issue = "27747")] + +/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat) +/// and [`[T]::join`](../../std/primitive.slice.html#method.join) +#[unstable(feature = "slice_concat_trait", issue = "27747")] +pub trait SliceConcat: Sized { + #[unstable(feature = "slice_concat_trait", issue = "27747")] /// The resulting type after concatenation type Output; - /// Flattens a slice of `T` into a single value `Self::Output`. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(["hello", "world"].concat(), "helloworld"); - /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn concat(&self) -> Self::Output; - - /// Flattens a slice of `T` into a single value `Self::Output`, placing a - /// given separator between each. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(["hello", "world"].join(" "), "hello world"); - /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); - /// ``` - #[stable(feature = "rename_connect_to_join", since = "1.3.0")] - fn join(&self, sep: &T) -> Self::Output; + /// Implementation of [`[T]::concat`](../../std/primitive.slice.html#method.concat) + #[unstable(feature = "slice_concat_trait", issue = "27747")] + fn concat(slice: &[Self]) -> Self::Output; - /// Flattens a slice of `T` into a single value `Self::Output`, placing a - /// given separator between each. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// assert_eq!(["hello", "world"].connect(" "), "hello world"); - /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] - fn connect(&self, sep: &T) -> Self::Output { - self.join(sep) - } + /// Implementation of [`[T]::join`](../../std/primitive.slice.html#method.join) + #[unstable(feature = "slice_concat_trait", issue = "27747")] + fn join(slice: &[Self], sep: &Separator) -> Self::Output; } #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] -impl> SliceConcatExt for [V] { +impl> SliceConcat for V { type Output = Vec; - fn concat(&self) -> Vec { - let size = self.iter().map(|slice| slice.borrow().len()).sum(); + fn concat(slice: &[Self]) -> Vec { + let size = slice.iter().map(|slice| slice.borrow().len()).sum(); let mut result = Vec::with_capacity(size); - for v in self { + for v in slice { result.extend_from_slice(v.borrow()) } result } - fn join(&self, sep: &T) -> Vec { - let mut iter = self.iter(); + fn join(slice: &[Self], sep: &T) -> Vec { + let mut iter = slice.iter(); let first = match iter.next() { Some(first) => first, None => return vec![], }; - let size = self.iter().map(|slice| slice.borrow().len()).sum::() + self.len() - 1; + let size = slice.iter().map(|slice| slice.borrow().len()).sum::() + slice.len() - 1; let mut result = Vec::with_capacity(size); result.extend_from_slice(first.borrow()); diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 70a93157c9ee2..37a1046d0942d 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -37,7 +37,7 @@ use core::unicode::conversions; use crate::borrow::ToOwned; use crate::boxed::Box; -use crate::slice::{SliceConcatExt, SliceIndex}; +use crate::slice::{SliceConcat, SliceIndex}; use crate::string::String; use crate::vec::Vec; @@ -74,16 +74,16 @@ pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] -impl> SliceConcatExt for [S] { +impl> SliceConcat for S { type Output = String; - fn concat(&self) -> String { - self.join("") + fn concat(slice: &[Self]) -> String { + Self::join(slice, "") } - fn join(&self, sep: &str) -> String { + fn join(slice: &[Self], sep: &str) -> String { unsafe { - String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) ) + String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) ) } } } @@ -126,7 +126,7 @@ macro_rules! copy_slice_and_advance { // Optimized join implementation that works for both Vec (T: Copy) and String's inner vec // Currently (2018-05-13) there is a bug with type inference and specialization (see issue #36262) -// For this reason SliceConcatExt is not specialized for T: Copy and SliceConcatExt is the +// For this reason SliceConcat is not specialized for T: Copy and SliceConcat is the // only user of this function. It is left in place for the time when that is fixed. // // the bounds for String-join are S: Borrow and for Vec-join Borrow<[T]> diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 551e982a3c685..3085c3d829653 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -71,9 +71,6 @@ //! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions //! that may succeed or fail. Like [`Option`], its variants are exported as //! well. -//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical -//! reasons, but shouldn't have to exist. It provides a few useful methods on -//! slices. //! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings. //! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated //! vector. diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index ce1e8e3319cf8..a863bebf4a264 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -60,9 +60,6 @@ pub use crate::boxed::Box; pub use crate::borrow::ToOwned; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use crate::slice::SliceConcatExt; -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use crate::string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] From 37d09a68f3a35d618678256238d508183bfb6caa Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sun, 7 Jul 2019 18:57:30 +0900 Subject: [PATCH 4/9] Resolve review comments --- src/librustdoc/clean/mod.rs | 6 +++--- src/test/rustdoc/inline_cross/impl_trait.rs | 10 ++-------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b5fcecf39413e..9b209a4f5f691 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1699,8 +1699,8 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.params.iter().enumerate() - .filter_map(|(i, param)| match param.kind { + let stripped_typarams = gens.params.iter() + .filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => None, ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name.as_symbol() == kw::SelfUpper { @@ -1708,7 +1708,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, return None; } if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { - impl_trait.insert((i as u32).into(), vec![]); + impl_trait.insert(param.index.into(), vec![]); return None; } Some(param.clean(cx)) diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 02c49145c762e..091baa9773ecf 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -3,17 +3,11 @@ extern crate impl_trait_aux; // @has impl_trait/fn.func.html -// @has - '//pre[@class="rust fn"]' '(_x: impl ' -// @has - '//pre[@class="rust fn"]' 'Clone' -// @has - '//pre[@class="rust fn"]' 'Into' -// @has - '//pre[@class="rust fn"]' "'a" +// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func; // @has impl_trait/struct.Foo.html -// @has - '//code[@id="method.v"]' '(_x: impl ' -// @has - '//code[@id="method.v"]' 'Clone' -// @has - '//code[@id="method.v"]' 'Into' -// @has - '//code[@id="method.v"]' "'a" +// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//code[@id="method.v"]' 'where' pub use impl_trait_aux::Foo; From 9c8432434f11c7b1ec303aca1300617b403e4b10 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 17:59:26 +0900 Subject: [PATCH 5/9] Associated type bound for inlined impl Trait doc --- src/librustdoc/clean/mod.rs | 93 +++++++++++++----- src/librustdoc/clean/simplify.rs | 96 ++++++++++--------- .../inline_cross/auxiliary/impl_trait_aux.rs | 4 + src/test/rustdoc/inline_cross/impl_trait.rs | 6 ++ 4 files changed, 131 insertions(+), 68 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9b209a4f5f691..d4af21f138bef 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1694,7 +1694,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, // since `Clean for ty::Predicate` would consume them. - let mut impl_trait = FxHashMap::>::default(); + let mut impl_trait = FxHashMap::>::default(); // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove @@ -1716,41 +1716,73 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); + // (param index, def id of trait) -> (name, type) + let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default(); + let mut where_predicates = preds.predicates.iter() .flat_map(|(p, _)| { - let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() { - if let ty::Param(param) = trait_ref.self_ty().sty { - Some(param.index) - } else { - None - } - } else if let Some(outlives) = p.to_opt_type_outlives() { - if let ty::Param(param) = outlives.skip_binder().0.sty { - Some(param.index) - } else { - None + let param_idx = (|| { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().sty { + return Some(param.index); + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.sty { + return Some(param.index); + } + } else if let ty::Predicate::Projection(proj) = p { + if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty { + return Some(param.index); + } } - } else { + None - }; + })(); let p = p.clean(cx)?; - if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) { - b.extend( - p.get_bounds() - .into_iter() - .flatten() - .cloned() - .filter(|b| !b.is_sized_bound(cx)) - ); - return None; + if let Some(param_idx) = param_idx { + if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + + let proj = match &p { + WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs)) + .and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))), + _ => None, + }; + if let Some(((_, trait_did, name), rhs)) = proj { + impl_trait_proj + .entry((param_idx, trait_did)) + .or_default() + .push((name.to_string(), rhs.clone())); + } + + return None; + } } Some(p) }) .collect::>(); + for ((param_idx, trait_did), bounds) in impl_trait_proj { + for (name, rhs) in bounds { + simplify::merge_bounds( + cx, + impl_trait.get_mut(¶m_idx.into()).unwrap(), + trait_did, + &name, + &rhs, + ); + } + } + // Move `TraitPredicate`s to the front. for (_, bounds) in impl_trait.iter_mut() { bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { @@ -2662,6 +2694,21 @@ impl Type { _ => false, } } + + pub fn projection(&self) -> Option<(&Type, DefId, &str)> { + let (self_, trait_, name) = match self { + QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return None, + }; + let trait_did = match **trait_ { + ResolvedPath { did, .. } => did, + _ => return None, + }; + Some((&self_, trait_did, name)) + } + } impl GetDefId for Type { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 36e6a6003df09..035e626d847ae 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -53,58 +53,21 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { - let (self_, trait_, name) = match *lhs { - clean::QPath { ref self_type, ref trait_, ref name } => { - (self_type, trait_, name) - } - _ => return true, - }; - let generic = match **self_ { - clean::Generic(ref s) => s, - _ => return true, + let (self_, trait_did, name) = if let Some(p) = lhs.projection() { + p + } else { + return true; }; - let trait_did = match **trait_ { - clean::ResolvedPath { did, .. } => did, + let generic = match self_ { + clean::Generic(s) => s, _ => return true, }; let bounds = match params.get_mut(generic) { Some(bound) => bound, None => return true, }; - !bounds.iter_mut().any(|b| { - let trait_ref = match *b { - clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, - }; - let (did, path) = match trait_ref.trait_ { - clean::ResolvedPath { did, ref mut path, ..} => (did, path), - _ => return false, - }; - // If this QPath's trait `trait_did` is the same as, or a supertrait - // of, the bound's trait `did` then we can keep going, otherwise - // this is just a plain old equality bound. - if !trait_is_same_or_supertrait(cx, did, trait_did) { - return false - } - let last = path.segments.last_mut().expect("segments were empty"); - match last.args { - PP::AngleBracketed { ref mut bindings, .. } => { - bindings.push(clean::TypeBinding { - name: name.clone(), - kind: clean::TypeBindingKind::Equality { - ty: rhs.clone(), - }, - }); - } - PP::Parenthesized { ref mut output, .. } => { - assert!(output.is_none()); - if *rhs != clean::Type::Tuple(Vec::new()) { - *output = Some(rhs.clone()); - } - } - }; - true - }) + + merge_bounds(cx, bounds, trait_did, name, rhs) }); // And finally, let's reassemble everything @@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { clauses } +pub fn merge_bounds( + cx: &clean::DocContext<'_>, + bounds: &mut Vec, + trait_did: DefId, + name: &str, + rhs: &clean::Type, +) -> bool { + !bounds.iter_mut().any(|b| { + let trait_ref = match *b { + clean::GenericBound::TraitBound(ref mut tr, _) => tr, + clean::GenericBound::Outlives(..) => return false, + }; + let (did, path) = match trait_ref.trait_ { + clean::ResolvedPath { did, ref mut path, ..} => (did, path), + _ => return false, + }; + // If this QPath's trait `trait_did` is the same as, or a supertrait + // of, the bound's trait `did` then we can keep going, otherwise + // this is just a plain old equality bound. + if !trait_is_same_or_supertrait(cx, did, trait_did) { + return false + } + let last = path.segments.last_mut().expect("segments were empty"); + match last.args { + PP::AngleBracketed { ref mut bindings, .. } => { + bindings.push(clean::TypeBinding { + name: name.to_string(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, + }); + } + PP::Parenthesized { ref mut output, .. } => { + assert!(output.is_none()); + if *rhs != clean::Type::Tuple(Vec::new()) { + *output = Some(rhs.clone()); + } + } + }; + true + }) +} + pub fn ty_params(mut params: Vec) -> Vec { for param in &mut params { match param.kind { diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 7807acbc4d61d..7b6e665b85f19 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -1,5 +1,9 @@ +use std::ops::Deref; + pub fn func<'a>(_x: impl Clone + Into> + 'a) {} +pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} + pub struct Foo; impl Foo { diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 091baa9773ecf..20d193aad16dc 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -7,6 +7,12 @@ extern crate impl_trait_aux; // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func; +// @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," +// @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func2; + // @has impl_trait/struct.Foo.html // @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//code[@id="method.v"]' 'where' From 65d391d05fa65591e91e61a327381008013b3454 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 20:42:45 +0900 Subject: [PATCH 6/9] Support nested `impl Trait` --- src/librustdoc/clean/mod.rs | 56 +++++++++++-------- .../inline_cross/auxiliary/impl_trait_aux.rs | 2 + src/test/rustdoc/inline_cross/impl_trait.rs | 6 ++ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d4af21f138bef..2a7b4de9bf3ce 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1717,10 +1717,12 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }).collect::>(); // (param index, def id of trait) -> (name, type) - let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default(); + let mut impl_trait_proj = + FxHashMap::)>>::default(); let mut where_predicates = preds.predicates.iter() .flat_map(|(p, _)| { + let mut projection = None; let param_idx = (|| { if let Some(trait_ref) = p.to_opt_poly_trait_ref() { if let ty::Param(param) = trait_ref.self_ty().sty { @@ -1730,8 +1732,9 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, if let ty::Param(param) = outlives.skip_binder().0.sty { return Some(param.index); } - } else if let ty::Predicate::Projection(proj) = p { - if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty { + } else if let ty::Predicate::Projection(p) = p { + if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty { + projection = Some(p); return Some(param.index); } } @@ -1751,16 +1754,15 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, .filter(|b| !b.is_sized_bound(cx)) ); - let proj = match &p { - WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs)) - .and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))), - _ => None, - }; - if let Some(((_, trait_did, name), rhs)) = proj { + let proj = projection + .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty)); + if let Some(((_, trait_did, name), rhs)) = + proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) + { impl_trait_proj - .entry((param_idx, trait_did)) + .entry(param_idx) .or_default() - .push((name.to_string(), rhs.clone())); + .push((trait_did, name.to_string(), rhs)); } return None; @@ -1771,18 +1773,6 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }) .collect::>(); - for ((param_idx, trait_did), bounds) in impl_trait_proj { - for (name, rhs) in bounds { - simplify::merge_bounds( - cx, - impl_trait.get_mut(¶m_idx.into()).unwrap(), - trait_did, - &name, - &rhs, - ); - } - } - // Move `TraitPredicate`s to the front. for (_, bounds) in impl_trait.iter_mut() { bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { @@ -1792,7 +1782,25 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }); } - cx.impl_trait_bounds.borrow_mut().extend(impl_trait); + for (param, mut bounds) in impl_trait { + if let crate::core::ImplTraitParam::ParamIndex(idx) = param { + if let Some(proj) = impl_trait_proj.remove(&idx) { + for (trait_did, name, rhs) in proj { + simplify::merge_bounds( + cx, + &mut bounds, + trait_did, + &name, + &rhs.clean(cx), + ); + } + } + } else { + unreachable!(); + } + + cx.impl_trait_bounds.borrow_mut().insert(param, bounds); + } // Type parameters and have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 7b6e665b85f19..e0f7c6d08ce2f 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -4,6 +4,8 @@ pub fn func<'a>(_x: impl Clone + Into> + 'a) {} pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} +pub fn func3(_x: impl Iterator> + Clone) {} + pub struct Foo; impl Foo { diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 20d193aad16dc..b08a070dcb74d 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -8,11 +8,17 @@ extern crate impl_trait_aux; pub use impl_trait_aux::func; // @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "func2(" // @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," // @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func2; +// @has impl_trait/fn.func3.html +// @has - '//pre[@class="rust fn"]' "func3(_x: impl Clone + Iterator>)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func3; + // @has impl_trait/struct.Foo.html // @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" // @!has - '//code[@id="method.v"]' 'where' From 946777d8cd149dd8cf5ecbb53f3c7e85326c38f7 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 20:45:59 +0900 Subject: [PATCH 7/9] Fix tidy --- src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs | 5 ++++- src/test/rustdoc/inline_cross/impl_trait.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index e0f7c6d08ce2f..24efe4297103f 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -2,7 +2,10 @@ use std::ops::Deref; pub fn func<'a>(_x: impl Clone + Into> + 'a) {} -pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} +pub fn func2( + _x: impl Deref> + Iterator, + _y: impl Iterator, +) {} pub fn func3(_x: impl Iterator> + Clone) {} diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index b08a070dcb74d..3a9f2f880798d 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -15,7 +15,8 @@ pub use impl_trait_aux::func; pub use impl_trait_aux::func2; // @has impl_trait/fn.func3.html -// @has - '//pre[@class="rust fn"]' "func3(_x: impl Clone + Iterator>)" +// @has - '//pre[@class="rust fn"]' "func3(" +// @has - '//pre[@class="rust fn"]' "_x: impl Clone + Iterator>)" // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func3; From ea3e804a8e6fffabfce9dbf27fd0d528b8096f31 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 21:14:44 +0900 Subject: [PATCH 8/9] Fix comment --- src/librustdoc/clean/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2a7b4de9bf3ce..1b7347ac3326e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1716,7 +1716,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); - // (param index, def id of trait) -> (name, type) + // param index -> [(DefId of trait, associated type name, type)] let mut impl_trait_proj = FxHashMap::)>>::default(); From b06ed52cfd57a971bf71bb8a4dab1a134cd041a3 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 9 Jul 2019 00:17:42 +0900 Subject: [PATCH 9/9] Remove unused dependencies --- Cargo.lock | 3 --- src/librustc_codegen_ssa/Cargo.toml | 1 - src/librustc_driver/Cargo.toml | 1 - src/librustc_interface/Cargo.toml | 1 - 4 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b5499ec6f351..f2ef5f5aacab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2985,7 +2985,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", @@ -3064,7 +3063,6 @@ dependencies = [ "rustc_target 0.0.0", "rustc_traits 0.0.0", "rustc_typeck 0.0.0", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", @@ -3128,7 +3126,6 @@ dependencies = [ "rustc_resolve 0.0.0", "rustc_traits 0.0.0", "rustc_typeck 0.0.0", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 343596feed25f..e7ee06df7e12d 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -13,7 +13,6 @@ test = false bitflags = "1.0.4" cc = "1.0.1" num_cpus = "1.0" -rustc-demangle = "0.1.15" memmap = "0.6" log = "0.4.5" libc = "0.2.44" diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index b28b015db7573..9a8473e1409d1 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -15,7 +15,6 @@ graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } rayon = { version = "0.2.0", package = "rustc-rayon" } -scoped-tls = "1.0" rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 82880d2198712..2712355d5379b 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -13,7 +13,6 @@ doctest = false log = "0.4" rayon = { version = "0.2.0", package = "rustc-rayon" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -scoped-tls = "1.0" syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" }