Skip to content

Commit c0889a6

Browse files
committed
fixyfixfix
1 parent 88935e0 commit c0889a6

File tree

6 files changed

+141
-29
lines changed

6 files changed

+141
-29
lines changed

compiler/rustc_hir_analysis/src/collect/lifetimes.rs

+87-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_middle::bug;
1818
use rustc_middle::hir::map::Map;
1919
use rustc_middle::hir::nested_filter;
2020
use rustc_middle::middle::resolve_lifetime::*;
21-
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
21+
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
2222
use rustc_span::def_id::DefId;
2323
use rustc_span::symbol::{sym, Ident};
2424
use rustc_span::Span;
@@ -1781,7 +1781,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
17811781

17821782
let mut late_bound = FxIndexSet::default();
17831783

1784-
let mut constrained_by_input = ConstrainedCollector::default();
1784+
let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
17851785
for arg_ty in decl.inputs {
17861786
constrained_by_input.visit_ty(arg_ty);
17871787
}
@@ -1834,12 +1834,44 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
18341834
debug!(?late_bound);
18351835
return Some(tcx.arena.alloc(late_bound));
18361836

1837-
#[derive(Default)]
1838-
struct ConstrainedCollector {
1837+
struct ConstrainedCollectorPostAstConv {
1838+
arg_is_constrained: Box<[bool]>,
1839+
}
1840+
1841+
use std::ops::ControlFlow;
1842+
use ty::Ty;
1843+
impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
1844+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
1845+
match t.kind() {
1846+
ty::Param(param_ty) => {
1847+
self.arg_is_constrained[param_ty.index as usize] = true;
1848+
}
1849+
ty::Projection(_) => return ControlFlow::Continue(()),
1850+
_ => (),
1851+
}
1852+
t.super_visit_with(self)
1853+
}
1854+
1855+
fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
1856+
ControlFlow::Continue(())
1857+
}
1858+
1859+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
1860+
debug!("r={:?}", r.kind());
1861+
if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
1862+
self.arg_is_constrained[region.index as usize] = true;
1863+
}
1864+
1865+
ControlFlow::Continue(())
1866+
}
1867+
}
1868+
1869+
struct ConstrainedCollector<'tcx> {
1870+
tcx: TyCtxt<'tcx>,
18391871
regions: FxHashSet<LocalDefId>,
18401872
}
18411873

1842-
impl<'v> Visitor<'v> for ConstrainedCollector {
1874+
impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
18431875
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
18441876
match ty.kind {
18451877
hir::TyKind::Path(
@@ -1850,6 +1882,56 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
18501882
// (defined above)
18511883
}
18521884

1885+
hir::TyKind::Path(hir::QPath::Resolved(
1886+
None,
1887+
hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
1888+
)) => {
1889+
// If this is a top level type alias attempt to "look through" it to see if the args
1890+
// are constrained, instead of assuming they are and inserting all the lifetimes.
1891+
// This is necessary for the following case:
1892+
// ```
1893+
// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
1894+
// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
1895+
// ```
1896+
// If we considered `'a` constrained then it would become late bound causing an error
1897+
// during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
1898+
// but appears in the output type `<() as Trait<'a>>::Assoc`.
1899+
1900+
let generics = self.tcx.generics_of(alias_def);
1901+
let mut walker = ConstrainedCollectorPostAstConv {
1902+
arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
1903+
};
1904+
walker.visit_ty(self.tcx.type_of(alias_def));
1905+
1906+
match segments.last() {
1907+
Some(hir::PathSegment { args: Some(args), .. }) => {
1908+
let tcx = self.tcx;
1909+
for constrained_arg in
1910+
args.args.iter().enumerate().flat_map(|(n, arg)| {
1911+
match walker.arg_is_constrained.get(n) {
1912+
Some(true) => Some(arg),
1913+
Some(false) => None,
1914+
None => {
1915+
tcx.sess.delay_span_bug(
1916+
*span,
1917+
format!(
1918+
"Incorrect generic arg count for alias {:?}",
1919+
alias_def
1920+
),
1921+
);
1922+
None
1923+
}
1924+
}
1925+
})
1926+
{
1927+
self.visit_generic_arg(constrained_arg);
1928+
}
1929+
}
1930+
Some(_) => (),
1931+
None => bug!("Path with no segments or self type"),
1932+
}
1933+
}
1934+
18531935
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
18541936
// consider only the lifetimes on the final
18551937
// segment; I am not sure it's even currently

src/test/ui/issues/issue-47511.stderr

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// check-pass
2+
3+
trait Gats<'a> {
4+
type Assoc;
5+
type Assoc2;
6+
}
7+
8+
trait Trait: for<'a> Gats<'a> {
9+
fn foo<'a>(_: &mut <Self as Gats<'a>>::Assoc) -> <Self as Gats<'a>>::Assoc2;
10+
}
11+
12+
impl<'a> Gats<'a> for () {
13+
type Assoc = &'a u32;
14+
type Assoc2 = ();
15+
}
16+
17+
type GatsAssoc<'a, T> = <T as Gats<'a>>::Assoc;
18+
type GatsAssoc2<'a, T> = <T as Gats<'a>>::Assoc2;
19+
20+
impl Trait for () {
21+
fn foo<'a>(_: &mut GatsAssoc<'a, Self>) -> GatsAssoc2<'a, Self> {}
22+
}
23+
24+
fn main() {}

src/test/ui/issues/issue-47511.rs src/test/ui/late-bound-lifetimes/issue-47511.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
// check-fail
2-
// known-bug: #47511
3-
4-
// Regression test for #47511: anonymous lifetimes can appear
5-
// unconstrained in a return type, but only if they appear just once
6-
// in the input, as the input to a projection.
1+
// check-pass
72

83
fn f(_: X) -> X {
94
unimplemented!()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// ensures that we don't ICE when there are too many args supplied to the alias.
2+
3+
trait Trait<'a> {
4+
type Assoc;
5+
}
6+
7+
type Alias<'a, T> = <T as Trait<'a>>::Assoc;
8+
9+
fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
10+
//~^ error: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0107]: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
2+
--> $DIR/mismatched_arg_count.rs:9:29
3+
|
4+
LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
5+
| ^^^^^ -- help: remove this lifetime argument
6+
| |
7+
| expected 1 lifetime argument
8+
|
9+
note: type alias defined here, with 1 lifetime parameter: `'a`
10+
--> $DIR/mismatched_arg_count.rs:7:6
11+
|
12+
LL | type Alias<'a, T> = <T as Trait<'a>>::Assoc;
13+
| ^^^^^ --
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)