Error initial pass
This commit is contained in:
parent
4e89811b46
commit
0bc340f756
@ -11,16 +11,17 @@
|
||||
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::hir::map as hir_map;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
use rustc_middle::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
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 std::convert::TryInto;
|
||||
@ -253,6 +254,97 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
let item = tcx.associated_item(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 {
|
||||
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
|
||||
associated_items
|
||||
.in_definition_order()
|
||||
.filter(|item| matches!(item.kind, ty::AssocKind::Fn))
|
||||
.for_each(|item| {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
|
||||
let sig = infcx.replace_bound_vars_with_placeholders(sig);
|
||||
let output = sig.output();
|
||||
let mut visitor = RegionsInGATs {
|
||||
tcx,
|
||||
gat: trait_item.def_id.to_def_id(),
|
||||
regions: FxHashSet::default(),
|
||||
};
|
||||
output.visit_with(&mut visitor);
|
||||
for input in sig.inputs() {
|
||||
let bounds = infcx.implied_outlives_bounds(ty::ParamEnv::empty(), hir_id, input, DUMMY_SP);
|
||||
debug!(?bounds);
|
||||
let mut clauses = FxHashSet::default();
|
||||
for bound in bounds {
|
||||
match bound {
|
||||
traits::query::OutlivesBound::RegionSubParam(r, p) => {
|
||||
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 {
|
||||
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));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
clauses.insert(clause);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
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> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
gat: DefId,
|
||||
// Which region appears and which parameter index its subsituted for
|
||||
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for RegionsInGATs<'tcx> {
|
||||
type BreakTy = !;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match t.kind() {
|
||||
ty::Projection(p) if p.item_def_id == self.gat => {
|
||||
let (_, substs) = p.trait_ref_and_own_substs(self.tcx);
|
||||
self.regions.extend(substs.iter().enumerate().filter_map(|(idx, subst)| {
|
||||
match subst.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => Some((lt, idx)),
|
||||
_ => None,
|
||||
}
|
||||
}));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
|
||||
Some(self.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
|
||||
|
41
src/test/ui/generic-associated-types/self-outlives-lint.rs
Normal file
41
src/test/ui/generic-associated-types/self-outlives-lint.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
// check-fail
|
||||
|
||||
trait Iterable {
|
||||
type Item<'x>;
|
||||
fn iter<'a>(&'a self) -> Self::Item<'a>;
|
||||
}
|
||||
|
||||
/*
|
||||
impl<T> Iterable for T {
|
||||
type Item<'a> = &'a T;
|
||||
fn iter<'a>(&'a self) -> Self::Item<'a> {
|
||||
self
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
trait Deserializer<T> {
|
||||
type Out<'x>;
|
||||
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
|
||||
}
|
||||
|
||||
/*
|
||||
impl<T> Deserializer<T> for () {
|
||||
type Out<'a> = &'a T;
|
||||
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
|
||||
}
|
||||
*/
|
||||
|
||||
trait Deserializer2<T> {
|
||||
type Out<'x>;
|
||||
fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
|
||||
}
|
||||
|
||||
trait Deserializer3<T, U> {
|
||||
type Out<'x, 'y>;
|
||||
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user