Some cleanup
This commit is contained in:
parent
0bc340f756
commit
a8c44d344b
@ -1,6 +1,7 @@
|
|||||||
use crate::check::{FnCtxt, Inherited};
|
use crate::check::{FnCtxt, Inherited};
|
||||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||||
|
|
||||||
|
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
@ -15,13 +16,14 @@ use rustc_infer::infer::TyCtxtInferExt;
|
|||||||
use rustc_middle::hir::map as hir_map;
|
use rustc_middle::hir::map as hir_map;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||||
use rustc_middle::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
|
use rustc_middle::ty::{
|
||||||
use rustc_session::lint;
|
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
|
||||||
|
WithConstness,
|
||||||
|
};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::{InferCtxtExt as _};
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::query::outlives_bounds::{InferCtxtExt as _};
|
|
||||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
|
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@ -255,75 +257,119 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Require that the user writes as where clauses on GATs the implicit
|
check_gat_where_clauses(tcx, trait_item, encl_trait_def_id);
|
||||||
// outlives bounds involving trait parameters in trait functions and
|
}
|
||||||
// lifetimes passed as GAT substs. See `self-outlives-lint` test.
|
|
||||||
|
/// Require that the user writes as where clauses on GATs the implicit
|
||||||
|
/// outlives bounds involving trait parameters in trait functions and
|
||||||
|
/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
|
||||||
|
fn check_gat_where_clauses(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
trait_item: &hir::TraitItem<'_>,
|
||||||
|
encl_trait_def_id: DefId,
|
||||||
|
) {
|
||||||
let item = tcx.associated_item(trait_item.def_id);
|
let item = tcx.associated_item(trait_item.def_id);
|
||||||
|
// If the current trait item isn't a type, it isn't a GAT
|
||||||
|
if !matches!(item.kind, ty::AssocKind::Type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
|
let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
|
||||||
if matches!(item.kind, ty::AssocKind::Type) && generics.params.len() > 0 {
|
// If the current associated type doesn't have any (own) params, it's not a GAT
|
||||||
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
|
if generics.params.len() == 0 {
|
||||||
associated_items
|
return;
|
||||||
.in_definition_order()
|
}
|
||||||
.filter(|item| matches!(item.kind, ty::AssocKind::Fn))
|
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
|
||||||
.for_each(|item| {
|
// For every function in this trait...
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
for item in
|
||||||
let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
|
associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
|
||||||
let sig = infcx.replace_bound_vars_with_placeholders(sig);
|
{
|
||||||
let output = sig.output();
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut visitor = RegionsInGATs {
|
let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
|
||||||
tcx,
|
let sig = infcx.replace_bound_vars_with_placeholders(sig);
|
||||||
gat: trait_item.def_id.to_def_id(),
|
// Find out what regions are passed as GAT substs
|
||||||
regions: FxHashSet::default(),
|
let mut visitor = GATSubstCollector {
|
||||||
};
|
tcx,
|
||||||
output.visit_with(&mut visitor);
|
gat: trait_item.def_id.to_def_id(),
|
||||||
for input in sig.inputs() {
|
regions: FxHashSet::default(),
|
||||||
let bounds = infcx.implied_outlives_bounds(ty::ParamEnv::empty(), hir_id, input, DUMMY_SP);
|
_types: FxHashSet::default(),
|
||||||
debug!(?bounds);
|
};
|
||||||
let mut clauses = FxHashSet::default();
|
sig.output().visit_with(&mut visitor);
|
||||||
for bound in bounds {
|
// If there are none, then it nothing to do
|
||||||
match bound {
|
if visitor.regions.is_empty() {
|
||||||
traits::query::OutlivesBound::RegionSubParam(r, p) => {
|
return;
|
||||||
for idx in visitor.regions.iter().filter(|(proj_r, _)| proj_r == &r).map(|r| r.1) {
|
}
|
||||||
let param_r = tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
let mut clauses = FxHashSet::default();
|
||||||
def_id: generics.params[idx].def_id,
|
// Otherwise, find the clauses required from implied bounds
|
||||||
index: idx as u32,
|
for input in sig.inputs() {
|
||||||
name: generics.params[idx].name,
|
// For a given input type, find the implied bounds
|
||||||
}));
|
let TypeOpOutput { output: bounds, .. } = match ty::ParamEnv::empty()
|
||||||
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(tcx.mk_ty(ty::Param(p)), param_r));
|
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty: input })
|
||||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
.fully_perform(&infcx)
|
||||||
clauses.insert(clause);
|
{
|
||||||
}
|
Ok(o) => o,
|
||||||
}
|
Err(_) => continue,
|
||||||
_ => {}
|
};
|
||||||
}
|
debug!(?bounds);
|
||||||
}
|
for bound in bounds {
|
||||||
debug!(?clauses);
|
match bound {
|
||||||
if !clauses.is_empty() {
|
traits::query::OutlivesBound::RegionSubParam(r, p) => {
|
||||||
let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
|
// If the implied bound is a `RegionSubParam` and
|
||||||
for clause in clauses {
|
// the region is used a GAT subst...
|
||||||
let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
|
for idx in visitor
|
||||||
debug!(?clause, ?found);
|
.regions
|
||||||
let mut error = tcx.sess.struct_span_err(
|
.iter()
|
||||||
trait_item.generics.span,
|
.filter(|(proj_r, _)| proj_r == &r)
|
||||||
&format!("Missing bound: {}", clause),
|
.map(|r| r.1)
|
||||||
|
{
|
||||||
|
// Then create a clause that is required on the GAT
|
||||||
|
let param_r = tcx.mk_region(ty::RegionKind::ReEarlyBound(
|
||||||
|
ty::EarlyBoundRegion {
|
||||||
|
def_id: generics.params[idx].def_id,
|
||||||
|
index: idx as u32,
|
||||||
|
name: generics.params[idx].name,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
let clause = ty::PredicateKind::TypeOutlives(
|
||||||
|
ty::OutlivesPredicate(tcx.mk_ty(ty::Param(p)), param_r),
|
||||||
);
|
);
|
||||||
error.emit();
|
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||||
|
clauses.insert(clause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
});
|
}
|
||||||
|
// If there are any missing clauses, emit an error
|
||||||
|
debug!(?clauses);
|
||||||
|
if !clauses.is_empty() {
|
||||||
|
let written_predicates: ty::GenericPredicates<'_> =
|
||||||
|
tcx.predicates_of(trait_item.def_id);
|
||||||
|
for clause in clauses {
|
||||||
|
let found =
|
||||||
|
written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
|
||||||
|
debug!(?clause, ?found);
|
||||||
|
let mut error = tcx.sess.struct_span_err(
|
||||||
|
trait_item.generics.span,
|
||||||
|
&format!("Missing bound: {}", clause),
|
||||||
|
);
|
||||||
|
error.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegionsInGATs<'tcx> {
|
struct GATSubstCollector<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
gat: DefId,
|
gat: DefId,
|
||||||
// Which region appears and which parameter index its subsituted for
|
// Which region appears and which parameter index its subsituted for
|
||||||
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
|
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
|
||||||
|
// Which params appears and which parameter index its subsituted for
|
||||||
|
_types: FxHashSet<(Ty<'tcx>, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<'tcx> for RegionsInGATs<'tcx> {
|
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
|
||||||
type BreakTy = !;
|
type BreakTy = !;
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
trait Iterable {
|
trait Iterable {
|
||||||
type Item<'x>;
|
type Item<'x>;
|
||||||
|
//~^ Missing bound
|
||||||
fn iter<'a>(&'a self) -> Self::Item<'a>;
|
fn iter<'a>(&'a self) -> Self::Item<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ impl<T> Iterable for T {
|
|||||||
|
|
||||||
trait Deserializer<T> {
|
trait Deserializer<T> {
|
||||||
type Out<'x>;
|
type Out<'x>;
|
||||||
|
//~^ Missing bound
|
||||||
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
|
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,12 +32,65 @@ impl<T> Deserializer<T> for () {
|
|||||||
|
|
||||||
trait Deserializer2<T> {
|
trait Deserializer2<T> {
|
||||||
type Out<'x>;
|
type Out<'x>;
|
||||||
|
//~^ Missing bound
|
||||||
fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
|
fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Deserializer3<T, U> {
|
trait Deserializer3<T, U> {
|
||||||
type Out<'x, 'y>;
|
type Out<'x, 'y>;
|
||||||
|
//~^ Missing bound
|
||||||
|
//~^^ Missing bound
|
||||||
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
|
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Deserializer4 {
|
||||||
|
type Out<'x>;
|
||||||
|
//~^ Missing bound
|
||||||
|
fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wrap<T>(T);
|
||||||
|
|
||||||
|
trait Des {
|
||||||
|
type Out<'x, D>;
|
||||||
|
//~^ Missing bound
|
||||||
|
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
impl Des for () {
|
||||||
|
type Out<'x, D> = &'x D;
|
||||||
|
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
trait Des2 {
|
||||||
|
type Out<'x, D>;
|
||||||
|
//~^ Missing bound
|
||||||
|
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
impl Des2 for () {
|
||||||
|
type Out<'x, D> = &'x D;
|
||||||
|
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
trait Des3 {
|
||||||
|
type Out<'x, D>;
|
||||||
|
//~^ Missing bound
|
||||||
|
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
impl Des3 for () {
|
||||||
|
type Out<'x, D> = &'x D;
|
||||||
|
fn des<'a, T>(&self, data: &'a T) -> Self::Out<'a, T> {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
error: Missing bound: Self: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:6:14
|
||||||
|
|
|
||||||
|
LL | type Item<'x>;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:21:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x>;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:34:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x>;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:40:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x, 'y>;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: Missing bound: U: 'y
|
||||||
|
--> $DIR/self-outlives-lint.rs:40:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x, 'y>;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:47:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x>;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:55:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x, D>;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:69:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x, D>;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Missing bound: T: 'x
|
||||||
|
--> $DIR/self-outlives-lint.rs:83:13
|
||||||
|
|
|
||||||
|
LL | type Out<'x, D>;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user