mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #70164 - eddyb:walk-generic-arg, r=nikomatsakis
ty/walk: iterate `GenericArg`s instead of `Ty`s. Before this PR, `Ty::walk` only iterated over `Ty`s, but that's becoming an increasing problem with `const` generics, as `ty::Const`s in `Substs` are missed by it. By working with `GenericArg` instead, we can handle both `Ty`s and `ty::Const`s, but also `ty::Region`s, which used to require ad-hoc mechanisms such as `push_regions`. I've also removed `TraitRef::input_types`, as it's both long obsolete, and easy to misuse.
This commit is contained in:
commit
209b2be09f
@ -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<Ty<'tcx>>,
|
||||
found_local_pattern: Option<&'tcx Pat<'tcx>>,
|
||||
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
|
||||
found_ty: Option<Ty<'tcx>>,
|
||||
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<Ty<'tcx>> {
|
||||
fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
|
||||
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<Self::Map> {
|
||||
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<hir::BodyId>,
|
||||
@ -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.
|
||||
|
@ -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::<Vec<_>>();
|
||||
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()
|
||||
});
|
||||
|
||||
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());
|
||||
|
||||
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
|
||||
|
@ -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()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T>(self, value: &T, region_set: &mut FxHashSet<ty::Region<'tcx>>) -> 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.
|
||||
|
@ -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<Item = Ty<'tcx>> + '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<Item = Ty<'tcx>>,
|
||||
J: Iterator<Item = Ty<'tcx>>,
|
||||
K: Iterator<Item = Ty<'tcx>>,
|
||||
{
|
||||
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<Item = Ty<'tcx>>,
|
||||
J: Iterator<Item = Ty<'tcx>>,
|
||||
K: Iterator<Item = Ty<'tcx>>,
|
||||
{
|
||||
type Item = Ty<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<Ty<'tcx>> {
|
||||
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<Item = Ty<'tcx>> + '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<PolyTraitRef<'tcx>> {
|
||||
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<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self)
|
||||
}
|
||||
|
||||
/// Iterator that walks the immediate children of `self`. Hence
|
||||
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
|
||||
/// (but not `i32`, like `walk`).
|
||||
pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter<walk::TypeWalkerArray<'tcx>> {
|
||||
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<F>(&'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 {
|
||||
|
@ -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<Component<'tcx>> {
|
||||
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)));
|
||||
}
|
||||
|
@ -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<Item = Ty<'tcx>> + '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<Item = Ty<'tcx>> + '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
|
||||
|
@ -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<TypeWalkerArray<'tcx>>;
|
||||
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<Bar<int>, 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<Ty<'tcx>> {
|
||||
fn next(&mut self) -> Option<GenericArg<'tcx>> {
|
||||
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<TypeWalkerArray<'_>> {
|
||||
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<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self)
|
||||
}
|
||||
|
||||
/// Iterator that walks the immediate children of `self`. Hence
|
||||
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
|
||||
/// (but not `i32`, like `walk`).
|
||||
pub fn walk_shallow(self) -> impl Iterator<Item = GenericArg<'tcx>> {
|
||||
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<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, 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());
|
||||
}
|
||||
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)
|
||||
}
|
||||
};
|
||||
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(..) => {}
|
||||
|
||||
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());
|
||||
ty::Array(ty, len) => {
|
||||
stack.push(len.into());
|
||||
stack.push(ty.into());
|
||||
}
|
||||
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.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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<Ty<'tcx>> {
|
||||
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<Vec<Ty<'t>>> {
|
||||
fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
|
||||
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<impl Iterator<Item = Ty<'tcx>>> {
|
||||
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<Ty<'_>> {
|
||||
debug!("ty_is_non_local_constructor({:?})", ty);
|
||||
|
||||
|
@ -536,18 +536,17 @@ fn trait_ref_type_vars<'a, 'tcx>(
|
||||
selcx: &mut SelectionContext<'a, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Vec<TyOrConstInferVar<'tcx>> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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<Vec<ty::PolyTraitRef<'tcx>>> = 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 `<Foo as SomeTrait>::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();
|
||||
}
|
||||
|
||||
// DO walk contained types, POSSIBLY reporting an error.
|
||||
}
|
||||
|
||||
_ => true, // walk contained types, if any
|
||||
}
|
||||
});
|
||||
|
||||
error
|
||||
// Walk contained types, if any.
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
|
@ -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<EvaluationResult, OverflowError> {
|
||||
// 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<T>` -> `Struct<U>`
|
||||
(&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
|
||||
let fields =
|
||||
def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>();
|
||||
let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => match ty.kind {
|
||||
ty::Param(p) => Some(p.index),
|
||||
_ => None,
|
||||
},
|
||||
|
||||
// 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);
|
||||
// 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<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`.
|
||||
let inner_source = field.subst(tcx, substs_a);
|
||||
let inner_target = field.subst(tcx, substs_b);
|
||||
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
|
||||
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<T>: Unsize<Field<U>>` predicate.
|
||||
// Construct the nested `TailField<T>: Unsize<TailField<U>>` 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);
|
||||
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
|
||||
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!(),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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),
|
||||
);
|
||||
|
@ -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.
|
||||
|
@ -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) =>
|
||||
|
@ -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<T>`, 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::<Vec<_>>();
|
||||
|
||||
// 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);
|
||||
|
||||
if own_counts.types == 0 {
|
||||
assert_eq!(generics.parent, None);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -315,25 +315,28 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pred: ty::Predicate<'tcx>,
|
||||
) -> FxHashSet<GenericParamDef> {
|
||||
pred.walk_tys()
|
||||
.flat_map(|t| {
|
||||
let mut regions = FxHashSet::default();
|
||||
tcx.collect_regions(&t, &mut regions);
|
||||
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().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),
|
||||
}
|
||||
})
|
||||
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()
|
||||
}
|
||||
|
@ -84,15 +84,6 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Clean<U> for ty::Binder<T>
|
||||
where
|
||||
T: Clean<U>,
|
||||
{
|
||||
fn clean(&self, cx: &DocContext<'_>) -> U {
|
||||
self.skip_binder().clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<ExternalCrate> for CrateNum {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
|
||||
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
|
||||
@ -305,59 +296,66 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
|
||||
let (trait_ref, ref bounds) = *self;
|
||||
impl Clean<Type> 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<GenericBound> 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<GenericBound> 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<GenericBound> for ty::TraitRef<'tcx> {
|
||||
impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
|
||||
(self, vec![]).clean(cx)
|
||||
(*self, &[][..]).clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,16 +493,17 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
|
||||
impl<'a> Clean<WherePredicate> 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<WherePredicate> for ty::SubtypePredicate<'tcx> {
|
||||
impl<'tcx> Clean<WherePredicate> 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<WherePredicate> for ty::SubtypePredicate<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Option<WherePredicate>>
|
||||
for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
|
||||
for ty::PolyOutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
|
||||
{
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
|
||||
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<Option<WherePredicate>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
|
||||
impl<'tcx> Clean<Option<WherePredicate>> for ty::PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
|
||||
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<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
|
||||
impl<'tcx> Clean<WherePredicate> 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<Type> for Ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let bounds = bounds
|
||||
let bounds: Vec<_> = bounds
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|pred| {
|
||||
@ -1703,7 +1703,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some((trait_ref.skip_binder(), bounds).clean(cx))
|
||||
Some((trait_ref, &bounds[..]).clean(cx))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
bounds.extend(regions);
|
||||
|
@ -8,8 +8,8 @@ extern crate coherence_lib as lib;
|
||||
use lib::*;
|
||||
|
||||
#[fundamental]
|
||||
struct Local;
|
||||
struct Local<T>(T);
|
||||
|
||||
impl Remote for Local {}
|
||||
impl Remote for Local<()> {}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user