diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 7824855fe057c..bb6e5700ccad4 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -7,52 +7,59 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Infer, Ty, TyVar}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; use std::borrow::Cow; -struct FindLocalByTypeVisitor<'a, 'tcx> { +struct FindHirNodeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - target_ty: Ty<'tcx>, - hir_map: Map<'tcx>, + target: GenericArg<'tcx>, + found_node_ty: Option>, found_local_pattern: Option<&'tcx Pat<'tcx>>, found_arg_pattern: Option<&'tcx Pat<'tcx>>, - found_ty: Option>, - found_closure: Option<&'tcx ExprKind<'tcx>>, + found_closure: Option<&'tcx Expr<'tcx>>, found_method_call: Option<&'tcx Expr<'tcx>>, } -impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: Map<'tcx>) -> Self { +impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { + fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self { Self { infcx, - target_ty, - hir_map, + target, + found_node_ty: None, found_local_pattern: None, found_arg_pattern: None, - found_ty: None, found_closure: None, found_method_call: None, } } - fn node_matches_type(&mut self, hir_id: HirId) -> Option> { + fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option> { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id)); match ty_opt { Some(ty) => { let ty = self.infcx.resolve_vars_if_possible(&ty); - if ty.walk().any(|inner_ty| { - inner_ty == self.target_ty - || match (&inner_ty.kind, &self.target_ty.kind) { - (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self - .infcx - .inner - .borrow_mut() - .type_variables - .sub_unified(a_vid, b_vid), + if ty.walk().any(|inner| { + inner == self.target + || match (inner.unpack(), self.target.unpack()) { + (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { + match (&inner_ty.kind, &target_ty.kind) { + ( + &ty::Infer(ty::TyVar(a_vid)), + &ty::Infer(ty::TyVar(b_vid)), + ) => self + .infcx + .inner + .borrow_mut() + .type_variables + .sub_unified(a_vid, b_vid), + _ => false, + } + } _ => false, } }) { @@ -66,36 +73,39 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::OnlyBodies(self.hir_map) + NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir()) } fn visit_local(&mut self, local: &'tcx Local<'tcx>) { - if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) { + if let (None, Some(ty)) = + (self.found_local_pattern, self.node_ty_contains_target(local.hir_id)) + { self.found_local_pattern = Some(&*local.pat); - self.found_ty = Some(ty); + self.found_node_ty = Some(ty); } intravisit::walk_local(self, local); } fn visit_body(&mut self, body: &'tcx Body<'tcx>) { for param in body.params { - if let (None, Some(ty)) = (self.found_arg_pattern, self.node_matches_type(param.hir_id)) + if let (None, Some(ty)) = + (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id)) { self.found_arg_pattern = Some(&*param.pat); - self.found_ty = Some(ty); + self.found_node_ty = Some(ty); } } intravisit::walk_body(self, body); } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.node_matches_type(expr.hir_id).is_some() { + if self.node_ty_contains_target(expr.hir_id).is_some() { match expr.kind { - ExprKind::Closure(..) => self.found_closure = Some(&expr.kind), + ExprKind::Closure(..) => self.found_closure = Some(&expr), ExprKind::MethodCall(..) => self.found_method_call = Some(&expr), _ => {} } @@ -213,6 +223,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (s, None, ty.prefix_string(), None, None) } + // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. pub fn need_type_info_err( &self, body_id: Option, @@ -223,7 +234,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, self.tcx.hir()); + let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into()); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -276,7 +287,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) }; - let ty_msg = match local_visitor.found_ty { + let ty_msg = match local_visitor.found_node_ty { Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); @@ -310,28 +321,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_code, ); - let suffix = match local_visitor.found_ty { + let suffix = match local_visitor.found_node_ty { Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { let fn_sig = substs.as_closure().sig(); let ret = fn_sig.output().skip_binder().to_string(); - if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure { - if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) { - closure_return_type_suggestion( - span, - &mut err, - &decl.output, - &body, - &descr, - &name, - &ret, - parent_name, - parent_descr, - ); - // We don't want to give the other suggestions when the problem is the - // closure return type. - return err; - } + let closure_decl_and_body_id = + local_visitor.found_closure.and_then(|closure| match &closure.kind { + ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)), + _ => None, + }); + + if let Some((decl, body_id)) = closure_decl_and_body_id { + closure_return_type_suggestion( + span, + &mut err, + &decl.output, + self.tcx.hir().body(body_id), + &descr, + &name, + &ret, + parent_name, + parent_descr, + ); + // We don't want to give the other suggestions when the problem is the + // closure return type. + return err; } // This shouldn't be reachable, but just in case we leave a reasonable fallback. diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 1cd6830b6a241..ed967f7ab3a0b 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -3,11 +3,9 @@ use crate::infer::{GenericKind, VerifyBound}; use crate::traits; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use smallvec::smallvec; - /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` /// obligation into a series of `'a: 'b` constraints and "verifys", as /// described on the module comment. The final constraints are emitted @@ -44,7 +42,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match ty.kind { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data), - _ => self.recursive_type_bound(ty), + _ => self.recursive_bound(ty.into()), } } @@ -144,25 +142,33 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - let recursive_bound = self.recursive_type_bound(ty); + let recursive_bound = self.recursive_bound(ty.into()); VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) } - fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::>(); - - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions - bounds.push(VerifyBound::AllBounds( - regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect(), - )); - - // remove bounds that must hold, since they are not interesting - bounds.retain(|b| !b.must_hold()); + fn recursive_bound(&self, parent: GenericArg<'tcx>) -> VerifyBound<'tcx> { + let mut bounds = parent + .walk_shallow() + .filter_map(|child| match child.unpack() { + GenericArgKind::Type(ty) => Some(self.type_bound(ty)), + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None } + } + GenericArgKind::Const(_) => Some(self.recursive_bound(child)), + }) + .filter(|bound| { + // Remove bounds that must hold, since they are not interesting. + !bound.must_hold() + }); - if bounds.len() == 1 { bounds.pop().unwrap() } else { VerifyBound::AllBounds(bounds) } + match (bounds.next(), bounds.next()) { + (Some(first), None) => first, + (first, second) => { + VerifyBound::AllBounds(first.into_iter().chain(second).chain(bounds).collect()) + } + } } /// Searches the environment for where-clauses like `G: 'a` where diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cff86e8f21837..84cf2258ac223 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -36,6 +36,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{GenericParamKind, PatKind}; use rustc_hir::{HirIdSet, Node}; use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::edition::Edition; @@ -104,11 +105,13 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) { - for leaf_ty in ty.walk() { - if leaf_ty.is_box() { - cx.struct_span_lint(BOX_POINTERS, span, |lint| { - lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit() - }); + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if leaf_ty.is_box() { + cx.struct_span_lint(BOX_POINTERS, span, |lint| { + lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit() + }); + } } } } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index a3d611a132592..7b23460eb6e4c 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -263,20 +263,6 @@ where // Region folder impl<'tcx> TyCtxt<'tcx> { - /// Collects the free and escaping regions in `value` into `region_set`. Returns - /// whether any late-bound regions were skipped - pub fn collect_regions(self, value: &T, region_set: &mut FxHashSet>) -> bool - where - T: TypeFoldable<'tcx>, - { - let mut have_bound_regions = false; - self.fold_regions(value, &mut have_bound_regions, |r, d| { - region_set.insert(self.mk_region(r.shifted_out_to_binder(d))); - r - }); - have_bound_regions - } - /// Folds the escaping and free regions in `value` using `f`, and /// sets `skipped_regions` to true if any late-bound region was found /// and skipped. diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 0ebd55a6c024c..1870856150f50 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -19,7 +19,6 @@ use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; -use crate::ty::walk::TypeWalker; use rustc_ast::ast::{self, Ident, Name}; use rustc_ast::node_id::{NodeId, NodeMap, NodeSet}; use rustc_attr as attr; @@ -1366,10 +1365,6 @@ impl<'tcx> TraitPredicate<'tcx> { self.trait_ref.def_id } - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { - self.trait_ref.input_types() - } - pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } @@ -1519,77 +1514,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } -// A custom iterator used by `Predicate::walk_tys`. -enum WalkTysIter<'tcx, I, J, K> -where - I: Iterator>, - J: Iterator>, - K: Iterator>, -{ - None, - One(Ty<'tcx>), - Two(Ty<'tcx>, Ty<'tcx>), - Types(I), - InputTypes(J), - ProjectionTypes(K), -} - -impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> -where - I: Iterator>, - J: Iterator>, - K: Iterator>, -{ - type Item = Ty<'tcx>; - - fn next(&mut self) -> Option> { - match *self { - WalkTysIter::None => None, - WalkTysIter::One(item) => { - *self = WalkTysIter::None; - Some(item) - } - WalkTysIter::Two(item1, item2) => { - *self = WalkTysIter::One(item2); - Some(item1) - } - WalkTysIter::Types(ref mut iter) => iter.next(), - WalkTysIter::InputTypes(ref mut iter) => iter.next(), - WalkTysIter::ProjectionTypes(ref mut iter) => iter.next(), - } - } -} - impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&'a self) -> impl Iterator> + 'a { - match *self { - ty::Predicate::Trait(ref data, _) => { - WalkTysIter::InputTypes(data.skip_binder().input_types()) - } - ty::Predicate::Subtype(binder) => { - let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - WalkTysIter::Two(a, b) - } - ty::Predicate::TypeOutlives(binder) => WalkTysIter::One(binder.skip_binder().0), - ty::Predicate::RegionOutlives(..) => WalkTysIter::None, - ty::Predicate::Projection(ref data) => { - let inner = data.skip_binder(); - WalkTysIter::ProjectionTypes( - inner.projection_ty.substs.types().chain(Some(inner.ty)), - ) - } - ty::Predicate::WellFormed(data) => WalkTysIter::One(data), - ty::Predicate::ObjectSafe(_trait_def_id) => WalkTysIter::None, - ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - WalkTysIter::Types(closure_substs.types()) - } - ty::Predicate::ConstEvaluatable(_, substs) => WalkTysIter::Types(substs.types()), - } - } - pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), @@ -2686,46 +2611,6 @@ impl<'tcx> ClosureKind { } } -impl<'tcx> TyS<'tcx> { - /// Iterator that walks `self` and any types reachable from - /// `self`, in depth-first order. Note that just walks the types - /// that appear in `self`, it does not descend into the fields of - /// structs or variants. For example: - /// - /// ```notrust - /// isize => { isize } - /// Foo> => { Foo>, Bar, isize } - /// [isize] => { [isize], isize } - /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { - TypeWalker::new(self) - } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo, u32>` yields the sequence `[Bar, u32]` - /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter> { - walk::walk_shallow(self) - } - - /// Walks `ty` and any types appearing within `ty`, invoking the - /// callback `f` on each type. If the callback returns `false`, then the - /// children of the current type are ignored. - /// - /// Note: prefer `ty.walk()` where possible. - pub fn maybe_walk(&'tcx self, mut f: F) - where - F: FnMut(Ty<'tcx>) -> bool, - { - let mut walker = self.walk(); - while let Some(ty) = walker.next() { - if !f(ty) { - walker.skip_current_subtree(); - } - } - } -} - impl BorrowKind { pub fn from_mutbl(m: hir::Mutability) -> BorrowKind { match m { diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 9dd96f2f2b507..950539fbb0a16 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -2,6 +2,7 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. +use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use smallvec::SmallVec; @@ -107,8 +108,9 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // fallback case: hard code // OutlivesProjectionComponents. Continue walking // through and constrain Pi. - let subcomponents = capture_components(tcx, ty); - out.push(Component::EscapingProjection(subcomponents)); + let mut subcomponents = smallvec![]; + compute_components_recursive(tcx, ty.into(), &mut subcomponents); + out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); } } @@ -153,26 +155,30 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // "bound regions list". In our representation, no such // list is maintained explicitly, because bound regions // themselves can be readily identified. - - push_region_constraints(ty, out); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, out); - } + compute_components_recursive(tcx, ty.into(), out); } } } -fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec> { - let mut temp = smallvec![]; - push_region_constraints(ty, &mut temp); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, &mut temp); +fn compute_components_recursive( + tcx: TyCtxt<'tcx>, + parent: GenericArg<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, +) { + for child in parent.walk_shallow() { + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out); + } + } } - temp.into_iter().collect() -} - -fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r))); } diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index ef815aaab75e9..f09327886872c 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -25,7 +25,6 @@ use rustc_macros::HashStable; use rustc_span::symbol::{kw, Symbol}; use rustc_target::abi::{Size, VariantIdx}; use rustc_target::spec::abi; -use smallvec::SmallVec; use std::borrow::Cow; use std::cmp::Ordering; use std::marker::PhantomData; @@ -755,14 +754,6 @@ impl<'tcx> TraitRef<'tcx> { self.substs.type_at(0) } - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - pub fn from_method( tcx: TyCtxt<'tcx>, trait_id: DefId, @@ -806,14 +797,6 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator> + 'b { - // Select only the "input types" from a trait-reference. For - // now this is all the types that appear in the - // trait-reference, but it should eventually exclude - // associated types. - self.substs.types() - } - pub fn erase_self_ty( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -2152,31 +2135,6 @@ impl<'tcx> TyS<'tcx> { } } - /// Pushes onto `out` the regions directly referenced from this type (but not - /// types reachable from this type via `walk_tys`). This ignores late-bound - /// regions binders. - pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) { - match self.kind { - Ref(region, _, _) => { - out.push(region); - } - Dynamic(ref obj, region) => { - out.push(region); - if let Some(principal) = obj.principal() { - out.extend(principal.skip_binder().substs.regions()); - } - } - Adt(_, substs) | Opaque(_, substs) => out.extend(substs.regions()), - Closure(_, ref substs) | Generator(_, ref substs, _) => out.extend(substs.regions()), - Projection(ref data) | UnnormalizedProjection(ref data) => { - out.extend(data.substs.regions()) - } - FnDef(..) | FnPtr(_) | GeneratorWitness(..) | Bool | Char | Int(_) | Uint(_) - | Float(_) | Str | Array(..) | Slice(_) | RawPtr(_) | Never | Tuple(..) - | Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {} - } - } - /// When we create a closure, we record its kind (i.e., what trait /// it implements) into its `ClosureSubsts` using a type /// parameter. This is kind of a phantom type, except that the diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs index da08fbcf14432..c7a317f39ad71 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/src/librustc_middle/ty/walk.rs @@ -1,13 +1,13 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use crate::ty::{self, Ty}; +use crate::ty; +use crate::ty::subst::{GenericArg, GenericArgKind}; use smallvec::{self, SmallVec}; // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. -pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8]; -pub type TypeWalkerStack<'tcx> = SmallVec>; +type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; pub struct TypeWalker<'tcx> { stack: TypeWalkerStack<'tcx>, @@ -15,11 +15,11 @@ pub struct TypeWalker<'tcx> { } impl<'tcx> TypeWalker<'tcx> { - pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: smallvec![ty], last_subtree: 1 } + pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> { + TypeWalker { stack: smallvec![root], last_subtree: 1 } } - /// Skips the subtree of types corresponding to the last type + /// Skips the subtree corresponding to the last type /// returned by `next()`. /// /// Example: Imagine you are walking `Foo, usize>`. @@ -37,102 +37,145 @@ impl<'tcx> TypeWalker<'tcx> { } impl<'tcx> Iterator for TypeWalker<'tcx> { - type Item = Ty<'tcx>; + type Item = GenericArg<'tcx>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { debug!("next(): stack={:?}", self.stack); - match self.stack.pop() { - None => None, - Some(ty) => { - self.last_subtree = self.stack.len(); - push_subtypes(&mut self.stack, ty); - debug!("next: stack={:?}", self.stack); - Some(ty) - } - } + let next = self.stack.pop()?; + self.last_subtree = self.stack.len(); + push_inner(&mut self.stack, next); + debug!("next: stack={:?}", self.stack); + Some(next) } } -pub fn walk_shallow(ty: Ty<'_>) -> smallvec::IntoIter> { - let mut stack = SmallVec::new(); - push_subtypes(&mut stack, ty); - stack.into_iter() +impl GenericArg<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```notrust + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker<'tcx> { + TypeWalker::new(self) + } + + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(self) -> impl Iterator> { + let mut stack = SmallVec::new(); + push_inner(&mut stack, self); + stack.into_iter() + } } -// We push types on the stack in reverse order so as to +impl<'tcx> super::TyS<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```notrust + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(&'tcx self) -> TypeWalker<'tcx> { + TypeWalker::new(self.into()) + } +} + +// We push `GenericArg`s on the stack in reverse order so as to // maintain a pre-order traversal. As of the time of this // writing, the fact that the traversal is pre-order is not // known to be significant to any code, but it seems like the // natural order one would expect (basically, the order of the // types as they are written). -fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { - match parent_ty.kind { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Infer(_) - | ty::Param(_) - | ty::Never - | ty::Error - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Foreign(..) => {} - ty::Array(ty, len) => { - if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val { - assert!(promoted.is_none()); - stack.extend(substs.types().rev()); +fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { + match parent.unpack() { + GenericArgKind::Type(parent_ty) => match parent_ty.kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Infer(_) + | ty::Param(_) + | ty::Never + | ty::Error + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Foreign(..) => {} + + ty::Array(ty, len) => { + stack.push(len.into()); + stack.push(ty.into()); } - stack.push(len.ty); - stack.push(ty); - } - ty::Slice(ty) => { - stack.push(ty); - } - ty::RawPtr(ref mt) => { - stack.push(mt.ty); - } - ty::Ref(_, ty, _) => { - stack.push(ty); - } - ty::Projection(ref data) | ty::UnnormalizedProjection(ref data) => { - stack.extend(data.substs.types().rev()); - } - ty::Dynamic(ref obj, ..) => { - stack.extend(obj.iter().rev().flat_map(|predicate| { - let (substs, opt_ty) = match *predicate.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), - ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), - ty::ExistentialPredicate::AutoTrait(_) => - // Empty iterator - { - (ty::InternalSubsts::empty(), None) - } - }; + ty::Slice(ty) => { + stack.push(ty.into()); + } + ty::RawPtr(mt) => { + stack.push(mt.ty.into()); + } + ty::Ref(lt, ty, _) => { + stack.push(ty.into()); + stack.push(lt.into()); + } + ty::Projection(data) | ty::UnnormalizedProjection(data) => { + stack.extend(data.substs.iter().copied().rev()); + } + ty::Dynamic(obj, lt) => { + stack.push(lt.into()); + stack.extend(obj.iter().rev().flat_map(|predicate| { + let (substs, opt_ty) = match *predicate.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), + ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), + ty::ExistentialPredicate::AutoTrait(_) => + // Empty iterator + { + (ty::InternalSubsts::empty(), None) + } + }; - substs.types().rev().chain(opt_ty) - })); - } - ty::Adt(_, substs) | ty::Opaque(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::Closure(_, ref substs) | ty::Generator(_, ref substs, _) => { - stack.extend(substs.types().rev()); - } - ty::GeneratorWitness(ts) => { - stack.extend(ts.skip_binder().iter().cloned().rev()); - } - ty::Tuple(..) => { - stack.extend(parent_ty.tuple_fields().rev()); - } - ty::FnDef(_, substs) => { - stack.extend(substs.types().rev()); - } - ty::FnPtr(sig) => { - stack.push(sig.skip_binder().output()); - stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); + substs.iter().copied().rev().chain(opt_ty.map(|ty| ty.into())) + })); + } + ty::Adt(_, substs) + | ty::Opaque(_, substs) + | ty::Closure(_, substs) + | ty::Generator(_, substs, _) + | ty::Tuple(substs) + | ty::FnDef(_, substs) => { + stack.extend(substs.iter().copied().rev()); + } + ty::GeneratorWitness(ts) => { + stack.extend(ts.skip_binder().iter().cloned().rev().map(|ty| ty.into())); + } + ty::FnPtr(sig) => { + stack.push(sig.skip_binder().output().into()); + stack.extend(sig.skip_binder().inputs().iter().cloned().rev().map(|ty| ty.into())); + } + }, + GenericArgKind::Lifetime(_) => {} + GenericArgKind::Const(parent_ct) => { + stack.push(parent_ct.ty.into()); + match parent_ct.val { + ty::ConstKind::Infer(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Value(_) => {} + + ty::ConstKind::Unevaluated(_, substs, _) => { + stack.extend(substs.iter().copied().rev()); + } + } } } } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1032ff413af41..d8ceda96a25e1 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -191,7 +191,7 @@ use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::obsolete::DefPathBasedNames; -use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::config::EntryFnType; use smallvec::SmallVec; @@ -442,9 +442,16 @@ fn check_recursion_limit<'tcx>( } fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count(); - let const_length = instance.substs.consts().flat_map(|ct| ct.ty.walk()).count(); - debug!(" => type length={}, const length={}", type_length, const_length); + let type_length = instance + .substs + .iter() + .flat_map(|&arg| arg.walk()) + .filter(|arg| match arg.unpack() { + GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, + GenericArgKind::Lifetime(_) => false, + }) + .count(); + debug!(" => type length={}", type_length); // Rust code can easily create exponentially-long types using only a // polynomial recursion depth. Even with the default recursion @@ -453,11 +460,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. let type_length_limit = *tcx.sess.type_length_limit.get(); - // We include the const length in the type length, as it's better - // to be overly conservative. - // FIXME(const_generics): we should instead uniformly walk through `substs`, - // ignoring lifetimes. - if type_length + const_length > type_length_limit { + if type_length > type_length_limit { // The instance name is already known to be too long for rustc. // Show only the first and last 32 characters to avoid blasting // the user's terminal with thousands of lines of type-name. diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c5b366ef57251..8f7a1b948e3fd 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -2,6 +2,7 @@ use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -92,7 +93,15 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - } fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { - for ty in ty.walk() { + for arg in ty.walk() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No constraints on lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + match ty.kind { ty::Ref(_, _, hir::Mutability::Mut) => { if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) { diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs index a642ae9823138..f1311382c5447 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/src/librustc_trait_selection/traits/coherence.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; +use std::iter; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -378,26 +379,36 @@ fn orphan_check_trait_ref<'tcx>( ty: Ty<'tcx>, in_crate: InCrate, ) -> Vec> { - if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() { - ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect() - } else { - vec![ty] + // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`, + // or maybe if this should be calling `ty_is_non_local_constructor`. + if ty_is_non_local(tcx, ty, in_crate).is_some() { + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + return inner_tys + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .collect(); + } } + + vec![ty] } let mut non_local_spans = vec![]; - for (i, input_ty) in - trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate() + for (i, input_ty) in trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .enumerate() { debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); - let non_local_tys = ty_is_non_local(input_ty, in_crate); + let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate); if non_local_tys.is_none() { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); return Ok(()); } else if let ty::Param(_) = input_ty.kind { debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); let local_type = trait_ref - .input_types() + .substs + .types() .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()); @@ -416,30 +427,53 @@ fn orphan_check_trait_ref<'tcx>( Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) } -fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option>> { +fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option>> { match ty_is_non_local_constructor(ty, in_crate) { Some(ty) => { - if !fundamental_ty(ty) { - Some(vec![ty]) - } else { - let tys: Vec<_> = ty - .walk_shallow() - .filter_map(|t| ty_is_non_local(t, in_crate)) - .flat_map(|i| i) + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + let tys: Vec<_> = inner_tys + .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate)) + .flatten() .collect(); if tys.is_empty() { None } else { Some(tys) } + } else { + Some(vec![ty]) } } None => None, } } -fn fundamental_ty(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Ref(..) => true, - ty::Adt(def, _) => def.is_fundamental(), - _ => false, - } +/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the +/// type parameters of the ADT, or `T`, respectively. For non-fundamental +/// types, returns `None`. +fn fundamental_ty_inner_tys( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option>> { + let (first_ty, rest_tys) = match ty.kind { + ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), + ty::Adt(def, substs) if def.is_fundamental() => { + let mut types = substs.types(); + + // FIXME(eddyb) actually validate `#[fundamental]` up-front. + match types.next() { + None => { + tcx.sess.span_err( + tcx.def_span(def.did), + "`#[fundamental]` requires at least one type parameter", + ); + + return None; + } + + Some(first_ty) => (first_ty, types), + } + } + _ => return None, + }; + + Some(iter::once(first_ty).chain(rest_tys)) } fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { @@ -451,6 +485,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { } } +// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`. fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option> { debug!("ty_is_non_local_constructor({:?})", ty); diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 09a33120ba7b6..49a4b96f8b7a1 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -536,18 +536,17 @@ fn trait_ref_type_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec> { - trait_ref + selcx + .infcx() + .resolve_vars_if_possible(&trait_ref) .skip_binder() // ok b/c this check doesn't care about regions - // FIXME(eddyb) walk over `GenericArg` to support const infer vars. - .input_types() - .map(|ty| selcx.infcx().resolve_vars_if_possible(&ty)) - // FIXME(eddyb) try using `maybe_walk` to skip *all* subtrees that - // don't contain inference variables, not just the outermost level. - // FIXME(eddyb) use `has_infer_types_or_const`. - .filter(|ty| ty.has_infer_types()) - .flat_map(|ty| ty.walk()) - // FIXME(eddyb) use `TyOrConstInferVar::maybe_from_generic_arg`. - .filter_map(TyOrConstInferVar::maybe_from_ty) + .substs + .iter() + // FIXME(eddyb) try using `skip_current_subtree` to skip everything that + // doesn't contain inference variables, not just the outermost level. + .filter(|arg| arg.has_infer_types_or_consts()) + .flat_map(|arg| arg.walk()) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg) .collect() } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 20b3fa908d201..d9a5b68dc1eb9 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -16,7 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{Applicability, FatalError}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; @@ -234,7 +234,7 @@ fn predicates_reference_self( tcx.predicates_of(trait_def_id) }; let self_ty = tcx.types.self_param; - let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty); + let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); predicates .predicates .iter() @@ -243,7 +243,7 @@ fn predicates_reference_self( match predicate { ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. - if data.skip_binder().input_types().skip(1).any(has_self_ty) { + if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None @@ -262,12 +262,8 @@ fn predicates_reference_self( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - if data - .skip_binder() - .projection_ty - .trait_ref(tcx) - .input_types() - .skip(1) + if data.skip_binder().projection_ty.trait_ref(tcx).substs[1..] + .iter() .any(has_self_ty) { Some(sp) @@ -725,19 +721,17 @@ fn contains_illegal_self_type_reference<'tcx>( // without knowing what `Self` is. let mut supertraits: Option>> = None; - let mut error = false; let self_ty = tcx.types.self_param; - ty.maybe_walk(|ty| { - match ty.kind { - ty::Param(_) => { - if ty == self_ty { - error = true; - } - false // no contained types to walk - } + let mut walker = ty.walk(); + while let Some(arg) = walker.next() { + if arg == self_ty.into() { + return true; + } - ty::Projection(ref data) => { + // Special-case projections (everything else is walked normally). + if let GenericArgKind::Type(ty) = arg.unpack() { + if let ty::Projection(ref data) = ty.kind { // This is a projected type `::X`. // Compute supertraits of current trait lazily. @@ -759,17 +753,18 @@ fn contains_illegal_self_type_reference<'tcx>( supertraits.as_ref().unwrap().contains(&projection_trait_ref); if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error + // Do not walk contained types, do not report error, do collect $200. + walker.skip_current_subtree(); } - } - _ => true, // walk contained types, if any + // DO walk contained types, POSSIBLY reporting an error. + } } - }); - error + // Walk contained types, if any. + } + + false } pub fn provide(providers: &mut ty::query::Providers<'_>) { diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 3d95824cdf00e..84c264f06db28 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -44,7 +44,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::ty::fast_reject; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{ self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; @@ -652,7 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> Result { - // In intercrate mode, whenever any of the types are unbound, + // In intercrate mode, whenever any of the generics are unbound, // there can always be an impl. Even if there are no impls in // this crate, perhaps the type would be unified with // something from another crate that does provide an impl. @@ -677,7 +677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let unbound_input_types = - stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); + stack.fresh_trait_ref.skip_binder().substs.types().any(|ty| ty.is_fresh()); // This check was an imperfect workaround for a bug in the old // intercrate mode; it should be removed when that goes away. if unbound_input_types && self.intercrate { @@ -1242,9 +1242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { - !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) - } + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_local_value(), _ => true, } } @@ -3048,20 +3046,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct` -> `Struct` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let fields = - def.all_fields().map(|field| tcx.type_of(field.did)).collect::>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); + let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { + GenericArgKind::Type(ty) => match ty.kind { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // Lifetimes aren't allowed to change during unsizing. + GenericArgKind::Lifetime(_) => None, + + GenericArgKind::Const(ct) => match ct.val { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, }; - let mut ty_params = GrowableBitSet::new_empty(); + + // The last field of the structure has to exist and contain type/const parameters. + let (tail_field, prefix_fields) = + def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; + let tail_field_ty = tcx.type_of(tail_field.did); + + let mut unsizing_params = GrowableBitSet::new_empty(); let mut found = false; - for ty in field.walk() { - if let ty::Param(p) = ty.kind { - ty_params.insert(p.index as usize); + for arg in tail_field_ty.walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); found = true; } } @@ -3069,31 +3078,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(Unimplemented); } - // Replace type parameters used in unsizing with - // Error and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let params = substs_a - .iter() - .enumerate() - .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); - let substs = tcx.mk_substs(params); - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, substs).references_error() { - return Err(Unimplemented); + // Ensure none of the other fields mention the parameters used + // in unsizing. + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + for field in prefix_fields { + for arg in tcx.type_of(field.did).walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + if unsizing_params.contains(i) { + return Err(Unimplemented); + } + } } } - // Extract `Field` and `Field` from `Struct` and `Struct`. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); + // Extract `TailField` and `TailField` from `Struct` and `Struct`. + let source_tail = tail_field_ty.subst(tcx, substs_a); + let target_tail = tail_field_ty.subst(tcx, substs_b); // Check that the source struct with the target's - // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { - if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); - let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); + // unsizing parameters is equal to the target. + let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, &k)| { + if unsizing_params.contains(i as u32) { substs_b[i] } else { k } + })); + let new_struct = tcx.mk_adt(def, substs); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) @@ -3101,15 +3110,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `Field: Unsize>` predicate. + // Construct the nested `TailField: Unsize>` predicate. nested.push(predicate_for_trait_def( tcx, obligation.param_env, obligation.cause.clone(), obligation.predicate.def_id(), obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], + source_tail, + &[target_tail.into()], )); } @@ -3253,15 +3262,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( - |(obligation_ty, impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty + obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any( + |(obligation_arg, impl_arg)| { + match (obligation_arg.unpack(), impl_arg.unpack()) { + (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => { + let simplified_obligation_ty = + fast_reject::simplify_type(self.tcx(), obligation_ty, true); + let simplified_impl_ty = + fast_reject::simplify_type(self.tcx(), impl_ty, false); + + simplified_obligation_ty.is_some() + && simplified_impl_ty.is_some() + && simplified_obligation_ty != simplified_impl_ty + } + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => { + // Lifetimes can never cause a rejection. + false + } + (GenericArgKind::Const(_), GenericArgKind::Const(_)) => { + // Conservatively ignore consts (i.e. assume they might + // unify later) until we have `fast_reject` support for + // them (if we'll ever need it, even). + false + } + _ => unreachable!(), + } }, ) } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 1eb41e0b4d1ae..6b38749e1e70a 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -4,7 +4,7 @@ use crate::traits::{self, AssocTypeBoundData}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; @@ -391,9 +391,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let mut subtys = ty0.walk(); + let mut walker = ty0.walk(); let param_env = self.param_env; - while let Some(ty) = subtys.next() { + while let Some(arg) = walker.next() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No WF constraints for lifetimes being present, any outlives + // obligations are handled by the parent (e.g. `ty::Ref`). + GenericArgKind::Lifetime(_) => continue, + + // FIXME(eddyb) this is wrong and needs to be replaced + // (see https://github.com/rust-lang/rust/pull/70107). + GenericArgKind::Const(_) => continue, + }; + match ty.kind { ty::Bool | ty::Char @@ -417,6 +429,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { ty::Array(subty, len) => { self.require_sized(subty, traits::SliceOrArrayElem); + // FIXME(eddyb) handle `GenericArgKind::Const` above instead. self.compute_array_len(*len); } @@ -433,7 +446,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::Projection(data) => { - subtys.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // subtree handled by compute_projection self.compute_projection(data); } @@ -504,7 +517,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // are not directly inspecting closure types // anyway, except via auto trait matching (which // only inspects the upvar types). - subtys.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // subtree handled by compute_projection for upvar_ty in substs.as_closure().upvar_tys() { self.compute(upvar_ty); } diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 28d5d25dd1ba2..612ab9b70ebc9 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -3,6 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::traits::{ Clause, Clauses, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory, }; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty, TyCtxt}; struct ClauseVisitor<'a, 'tcx> { @@ -210,7 +211,8 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { _ => NodeKind::Other, }; - let mut input_tys = FxHashSet::default(); + // FIXME(eddyb) isn't the unordered nature of this a hazard? + let mut inputs = FxHashSet::default(); match node_kind { // In a trait impl, we assume that the header trait ref and all its @@ -218,14 +220,14 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { NodeKind::TraitImpl => { let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); - input_tys.extend(trait_ref.input_types().flat_map(|ty| ty.walk())); + inputs.extend(trait_ref.substs.iter().flat_map(|&arg| arg.walk())); } // In an inherent impl, we assume that the receiver type and all its // constituents are well-formed. NodeKind::InherentImpl => { let self_ty = tcx.type_of(def_id); - input_tys.extend(self_ty.walk()); + inputs.extend(self_ty.walk()); } // In an fn, we assume that the arguments and all their constituents are @@ -234,16 +236,27 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { let fn_sig = tcx.fn_sig(def_id); let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); - input_tys.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); } NodeKind::Other => (), } let clauses = clauses.chain( - input_tys + inputs .into_iter() - .map(|ty| DomainGoal::FromEnv(FromEnv::Ty(ty))) + .filter_map(|arg| { + match arg.unpack() { + GenericArgKind::Type(ty) => Some(FromEnv::Ty(ty)), + + // FIXME(eddyb) no WF conditions from lifetimes? + GenericArgKind::Lifetime(_) => None, + + // FIXME(eddyb) support const generics in Chalk + GenericArgKind::Const(_) => None, + } + }) + .map(DomainGoal::FromEnv) .map(|domain_goal| domain_goal.into_program_clause()) .map(Clause::Implies), ); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c3ebcbfc832d1..ed7ec1c3b10da 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -737,8 +737,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let default_needs_object_self = |param: &ty::GenericParamDef| { if let GenericParamDefKind::Type { has_default, .. } = param.kind { if is_object && has_default { + let default_ty = tcx.at(span).type_of(param.def_id); let self_param = tcx.types.self_param; - if tcx.at(span).type_of(param.def_id).walk().any(|ty| ty == self_param) { + if default_ty.walk().any(|arg| arg == self_param.into()) { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -1617,7 +1618,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Predicate::Projection(pred) => { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. - let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); + let references_self = + pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); // If the projection output contains `Self`, force the user to // elaborate it explicitly to avoid a lot of complexity. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5a97a2af120d0..ff3493eb6de6d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -563,30 +563,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { while !queue.is_empty() { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => { - if unsize_did == tr.def_id() { - let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; - if let ty::Tuple(..) = sty { + let trait_pred = match obligation.predicate { + ty::Predicate::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { + if unsize_did == trait_pred.def_id() { + let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); + if let ty::Tuple(..) = unsize_ty.kind { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } } - *tr + trait_pred } _ => { coercion.obligations.push(obligation); continue; } }; - match selcx.select(&obligation.with(trait_ref)) { + match selcx.select(&obligation.with(trait_pred)) { // Uncertain or unimplemented. Ok(None) => { - if trait_ref.def_id() == unsize_did { - let trait_ref = self.resolve_vars_if_possible(&trait_ref); - let self_ty = trait_ref.skip_binder().self_ty(); - let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap(); - debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref); + if trait_pred.def_id() == unsize_did { + let trait_pred = self.resolve_vars_if_possible(&trait_pred); + let self_ty = trait_pred.skip_binder().self_ty(); + let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); match (&self_ty.kind, &unsize_ty.kind) { (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) if self.type_var_is_sized(*v) => diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 293c4feac62f5..eebc34d3db8ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,6 +102,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items; use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; +use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -1767,7 +1768,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { let def_id = tcx.hir().local_def_id(it.hir_id); let pty_ty = tcx.type_of(def_id); let generics = tcx.generics_of(def_id); - check_bounds_are_used(tcx, &generics, pty_ty); + check_type_params_are_used(tcx, &generics, pty_ty); } hir::ItemKind::ForeignMod(ref m) => { check_abi(tcx, it.span, m.abi); @@ -4139,20 +4140,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `FulfillmentError`. let mut referenced_in = final_arg_types .iter() - .map(|(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty))) + .map(|&(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.resolve_vars_if_possible(&ty); // We walk the argument type because the argument's type could have // been `Option`, but the `FulfillmentError` references `T`. - ty.walk() - .filter(|&ty| ty == predicate.skip_binder().self_ty()) - .map(move |_| *i) + if ty.walk().any(|arg| arg == predicate.skip_binder().self_ty().into()) { + Some(i) + } else { + None + } }) .collect::>(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. + referenced_in.sort(); referenced_in.dedup(); if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { @@ -5744,43 +5748,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -pub fn check_bounds_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { - let own_counts = generics.own_counts(); - debug!( - "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})", - own_counts.types, own_counts.consts, ty - ); +fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { + debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + + assert_eq!(generics.parent, None); - if own_counts.types == 0 { + if generics.own_counts().types == 0 { return; } - // Make a vector of booleans initially `false`; set to `true` when used. - let mut types_used = vec![false; own_counts.types]; + let mut params_used = BitSet::new_empty(generics.params.len()); - for leaf_ty in ty.walk() { - if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.kind { - debug!("found use of ty param num {}", index); - types_used[index as usize - own_counts.lifetimes] = true; - } else if let ty::Error = leaf_ty.kind { - // If there is already another error, do not emit - // an error for not using a type parameter. - assert!(tcx.sess.has_errors()); - return; + if ty.references_error() { + // If there is already another error, do not emit + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); + return; + } + + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if let ty::Param(param) = leaf_ty.kind { + debug!("found use of ty param {:?}", param); + params_used.insert(param.index); + } } } - let types = generics.params.iter().filter(|param| match param.kind { - ty::GenericParamDefKind::Type { .. } => true, - _ => false, - }); - for (&used, param) in types_used.iter().zip(types) { - if !used { - let id = tcx.hir().as_local_hir_id(param.def_id).unwrap(); - let span = tcx.hir().span(id); - struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name) + for param in &generics.params { + if !params_used.contains(param.index) { + if let ty::GenericParamDefKind::Type { .. } = param.kind { + let span = tcx.def_span(param.def_id); + struct_span_err!( + tcx.sess, + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) .span_label(span, "unused type parameter") .emit(); + } } } } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index df7c535ff3bb3..2abca30246905 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -119,7 +119,15 @@ fn insert_required_predicates_to_be_wf<'tcx>( required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for ty in field_ty.walk() { + for arg in field_ty.walk() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No predicates from lifetimes or constants, except potentially + // constants' types, but `walk` will get to them as well. + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, + }; + match ty.kind { // The field is of type &'a T which means that we will have // a predicate requirement of T: 'a (T outlives 'a). @@ -303,7 +311,7 @@ pub fn check_explicit_predicates<'tcx>( // 'b`. if let Some(self_ty) = ignored_self_ty { if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.walk().any(|ty| ty == self_ty) { + if ty.walk().any(|arg| arg == self_ty.into()) { debug!("skipping self ty = {:?}", &ty); continue; } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 73df844a91b80..eb8aec708a639 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -315,25 +315,28 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> FxHashSet { - pred.walk_tys() - .flat_map(|t| { - let mut regions = FxHashSet::default(); - tcx.collect_regions(&t, &mut regions); - - regions.into_iter().flat_map(|r| { - match r { - // We only care about late bound regions, as we need to add them - // to the 'for<>' section - &ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => { - Some(GenericParamDef { - name: name.to_string(), - kind: GenericParamDefKind::Lifetime, - }) - } - &ty::ReVar(_) | &ty::ReEarlyBound(_) | &ty::ReStatic => None, - _ => panic!("Unexpected region type {:?}", r), - } - }) + let regions = match pred { + ty::Predicate::Trait(poly_trait_pred, _) => { + tcx.collect_referenced_late_bound_regions(&poly_trait_pred) + } + ty::Predicate::Projection(poly_proj_pred) => { + tcx.collect_referenced_late_bound_regions(&poly_proj_pred) + } + _ => return FxHashSet::default(), + }; + + regions + .into_iter() + .filter_map(|br| { + match br { + // We only care about named late bound regions, as we need to add them + // to the 'for<>' section + ty::BrNamed(_, name) => Some(GenericParamDef { + name: name.to_string(), + kind: GenericParamDefKind::Lifetime, + }), + _ => None, + } }) .collect() } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f41114839020e..5c35dc5513266 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -84,15 +84,6 @@ impl, U> Clean> for Option { } } -impl Clean for ty::Binder -where - T: Clean, -{ - fn clean(&self, cx: &DocContext<'_>) -> U { - self.skip_binder().clean(cx) - } -} - impl Clean for CrateNum { fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate { let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; @@ -305,59 +296,66 @@ impl Clean for hir::GenericBound<'_> { } } -impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec) { - fn clean(&self, cx: &DocContext<'_>) -> GenericBound { - let (trait_ref, ref bounds) = *self; +impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &DocContext<'_>) -> Type { + let (trait_ref, bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); let path = external_path( cx, cx.tcx.item_name(trait_ref.def_id), Some(trait_ref.def_id), true, - bounds.clone(), + bounds.to_vec(), trait_ref.substs, ); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); + ResolvedPath { path, param_names: None, did: trait_ref.def_id, is_generic: false } + } +} + +impl<'tcx> Clean for ty::TraitRef<'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { + GenericBound::TraitBound( + PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] }, + hir::TraitBoundModifier::None, + ) + } +} + +impl Clean for (ty::PolyTraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { + let (poly_trait_ref, bounds) = *self; + let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap(); + // collect any late bound regions - let mut late_bounds = vec![]; - for ty_s in trait_ref.input_types().skip(1) { - if let ty::Tuple(ts) = ty_s.kind { - for &ty_s in ts { - if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().kind { - if let &ty::RegionKind::ReLateBound(..) = *reg { - debug!(" hit an ReLateBound {:?}", reg); - if let Some(Lifetime(name)) = reg.clean(cx) { - late_bounds.push(GenericParamDef { - name, - kind: GenericParamDefKind::Lifetime, - }); - } - } - } - } - } - } + let late_bound_regions: Vec<_> = cx + .tcx + .collect_referenced_late_bound_regions(&poly_trait_ref) + .into_iter() + .filter_map(|br| match br { + ty::BrNamed(_, name) => Some(GenericParamDef { + name: name.to_string(), + kind: GenericParamDefKind::Lifetime, + }), + _ => None, + }) + .collect(); GenericBound::TraitBound( PolyTrait { - trait_: ResolvedPath { - path, - param_names: None, - did: trait_ref.def_id, - is_generic: false, - }, - generic_params: late_bounds, + trait_: (*poly_trait_ref.skip_binder(), bounds).clean(cx), + generic_params: late_bound_regions, }, hir::TraitBoundModifier::None, ) } } -impl<'tcx> Clean for ty::TraitRef<'tcx> { +impl<'tcx> Clean for ty::PolyTraitRef<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> GenericBound { - (self, vec![]).clean(cx) + (*self, &[][..]).clean(cx) } } @@ -495,16 +493,17 @@ impl<'a> Clean> for ty::Predicate<'a> { } } -impl<'a> Clean for ty::TraitPredicate<'a> { +impl<'a> Clean for ty::PolyTraitPredicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { + let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); WherePredicate::BoundPredicate { - ty: self.trait_ref.self_ty().clean(cx), - bounds: vec![self.trait_ref.clean(cx)], + ty: poly_trait_ref.self_ty().clean(cx), + bounds: vec![poly_trait_ref.clean(cx)], } } } -impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { +impl<'tcx> Clean for ty::PolySubtypePredicate<'tcx> { fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate { panic!( "subtype predicates are an internal rustc artifact \ @@ -514,10 +513,10 @@ impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { } impl<'tcx> Clean> - for ty::OutlivesPredicate, ty::Region<'tcx>> + for ty::PolyOutlivesPredicate, ty::Region<'tcx>> { fn clean(&self, cx: &DocContext<'_>) -> Option { - let ty::OutlivesPredicate(ref a, ref b) = *self; + let ty::OutlivesPredicate(a, b) = self.skip_binder(); if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) { return None; @@ -530,9 +529,9 @@ impl<'tcx> Clean> } } -impl<'tcx> Clean> for ty::OutlivesPredicate, ty::Region<'tcx>> { +impl<'tcx> Clean> for ty::PolyOutlivesPredicate, ty::Region<'tcx>> { fn clean(&self, cx: &DocContext<'_>) -> Option { - let ty::OutlivesPredicate(ref ty, ref lt) = *self; + let ty::OutlivesPredicate(ty, lt) = self.skip_binder(); if let ty::ReEmpty(_) = lt { return None; @@ -545,9 +544,10 @@ impl<'tcx> Clean> for ty::OutlivesPredicate, ty: } } -impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { +impl<'tcx> Clean for ty::PolyProjectionPredicate<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { - WherePredicate::EqPredicate { lhs: self.projection_ty.clean(cx), rhs: self.ty.clean(cx) } + let ty::ProjectionPredicate { projection_ty, ty } = *self.skip_binder(); + WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) } } } @@ -1674,7 +1674,7 @@ impl<'tcx> Clean for Ty<'tcx> { } } - let bounds = bounds + let bounds: Vec<_> = bounds .predicates .iter() .filter_map(|pred| { @@ -1703,7 +1703,7 @@ impl<'tcx> Clean for Ty<'tcx> { }) .collect(); - Some((trait_ref.skip_binder(), bounds).clean(cx)) + Some((trait_ref, &bounds[..]).clean(cx)) }) .collect::>(); bounds.extend(regions); diff --git a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs index 49b3abc99b731..bc1e18b657f31 100644 --- a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs +++ b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs @@ -8,8 +8,8 @@ extern crate coherence_lib as lib; use lib::*; #[fundamental] -struct Local; +struct Local(T); -impl Remote for Local {} +impl Remote for Local<()> {} fn main() {}