Skip to content

Commit 0bc340f

Browse files
committed
Error initial pass
1 parent 4e89811 commit 0bc340f

File tree

2 files changed

+139
-6
lines changed

2 files changed

+139
-6
lines changed

compiler/rustc_typeck/src/check/wfcheck.rs

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ use rustc_hir::intravisit::Visitor;
1111
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
1212
use rustc_hir::lang_items::LangItem;
1313
use rustc_hir::ItemKind;
14+
use rustc_infer::infer::TyCtxtInferExt;
1415
use rustc_middle::hir::map as hir_map;
15-
use rustc_middle::ty::subst::{InternalSubsts, Subst};
16+
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
1617
use rustc_middle::ty::trait_def::TraitSpecializationKind;
17-
use rustc_middle::ty::{
18-
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
19-
};
18+
use rustc_middle::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
19+
use rustc_session::lint;
2020
use rustc_session::parse::feature_err;
2121
use rustc_span::symbol::{sym, Ident, Symbol};
22-
use rustc_span::Span;
23-
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
22+
use rustc_span::{DUMMY_SP, Span};
23+
use rustc_trait_selection::traits::query::evaluate_obligation::{InferCtxtExt as _};
24+
use rustc_trait_selection::traits::query::outlives_bounds::{InferCtxtExt as _};
2425
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
2526

2627
use std::convert::TryInto;
@@ -253,6 +254,97 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
253254
.emit();
254255
}
255256
}
257+
258+
// Require that the user writes as where clauses on GATs the implicit
259+
// outlives bounds involving trait parameters in trait functions and
260+
// lifetimes passed as GAT substs. See `self-outlives-lint` test.
261+
let item = tcx.associated_item(trait_item.def_id);
262+
let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
263+
if matches!(item.kind, ty::AssocKind::Type) && generics.params.len() > 0 {
264+
let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
265+
associated_items
266+
.in_definition_order()
267+
.filter(|item| matches!(item.kind, ty::AssocKind::Fn))
268+
.for_each(|item| {
269+
tcx.infer_ctxt().enter(|infcx| {
270+
let sig: ty::Binder<'_, ty::FnSig<'_>> = tcx.fn_sig(item.def_id);
271+
let sig = infcx.replace_bound_vars_with_placeholders(sig);
272+
let output = sig.output();
273+
let mut visitor = RegionsInGATs {
274+
tcx,
275+
gat: trait_item.def_id.to_def_id(),
276+
regions: FxHashSet::default(),
277+
};
278+
output.visit_with(&mut visitor);
279+
for input in sig.inputs() {
280+
let bounds = infcx.implied_outlives_bounds(ty::ParamEnv::empty(), hir_id, input, DUMMY_SP);
281+
debug!(?bounds);
282+
let mut clauses = FxHashSet::default();
283+
for bound in bounds {
284+
match bound {
285+
traits::query::OutlivesBound::RegionSubParam(r, p) => {
286+
for idx in visitor.regions.iter().filter(|(proj_r, _)| proj_r == &r).map(|r| r.1) {
287+
let param_r = tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
288+
def_id: generics.params[idx].def_id,
289+
index: idx as u32,
290+
name: generics.params[idx].name,
291+
}));
292+
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(tcx.mk_ty(ty::Param(p)), param_r));
293+
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
294+
clauses.insert(clause);
295+
}
296+
}
297+
_ => {}
298+
}
299+
}
300+
debug!(?clauses);
301+
if !clauses.is_empty() {
302+
let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
303+
for clause in clauses {
304+
let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
305+
debug!(?clause, ?found);
306+
let mut error = tcx.sess.struct_span_err(
307+
trait_item.generics.span,
308+
&format!("Missing bound: {}", clause),
309+
);
310+
error.emit();
311+
}
312+
}
313+
}
314+
})
315+
});
316+
}
317+
}
318+
319+
struct RegionsInGATs<'tcx> {
320+
tcx: TyCtxt<'tcx>,
321+
gat: DefId,
322+
// Which region appears and which parameter index its subsituted for
323+
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
324+
}
325+
326+
impl<'tcx> TypeVisitor<'tcx> for RegionsInGATs<'tcx> {
327+
type BreakTy = !;
328+
329+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
330+
match t.kind() {
331+
ty::Projection(p) if p.item_def_id == self.gat => {
332+
let (_, substs) = p.trait_ref_and_own_substs(self.tcx);
333+
self.regions.extend(substs.iter().enumerate().filter_map(|(idx, subst)| {
334+
match subst.unpack() {
335+
GenericArgKind::Lifetime(lt) => Some((lt, idx)),
336+
_ => None,
337+
}
338+
}));
339+
}
340+
_ => {}
341+
}
342+
t.super_visit_with(self)
343+
}
344+
345+
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
346+
Some(self.tcx)
347+
}
256348
}
257349

258350
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#![feature(generic_associated_types)]
2+
3+
// check-fail
4+
5+
trait Iterable {
6+
type Item<'x>;
7+
fn iter<'a>(&'a self) -> Self::Item<'a>;
8+
}
9+
10+
/*
11+
impl<T> Iterable for T {
12+
type Item<'a> = &'a T;
13+
fn iter<'a>(&'a self) -> Self::Item<'a> {
14+
self
15+
}
16+
}
17+
*/
18+
19+
trait Deserializer<T> {
20+
type Out<'x>;
21+
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
22+
}
23+
24+
/*
25+
impl<T> Deserializer<T> for () {
26+
type Out<'a> = &'a T;
27+
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
28+
}
29+
*/
30+
31+
trait Deserializer2<T> {
32+
type Out<'x>;
33+
fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
34+
}
35+
36+
trait Deserializer3<T, U> {
37+
type Out<'x, 'y>;
38+
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
39+
}
40+
41+
fn main() {}

0 commit comments

Comments
 (0)