fixyfixfix
This commit is contained in:
parent
88935e0bea
commit
c0889a6005
@ -18,7 +18,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_lifetime::*;
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
@ -1781,7 +1781,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
||||
|
||||
let mut late_bound = FxIndexSet::default();
|
||||
|
||||
let mut constrained_by_input = ConstrainedCollector::default();
|
||||
let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
|
||||
for arg_ty in decl.inputs {
|
||||
constrained_by_input.visit_ty(arg_ty);
|
||||
}
|
||||
@ -1834,12 +1834,44 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
||||
debug!(?late_bound);
|
||||
return Some(tcx.arena.alloc(late_bound));
|
||||
|
||||
#[derive(Default)]
|
||||
struct ConstrainedCollector {
|
||||
struct ConstrainedCollectorPostAstConv {
|
||||
arg_is_constrained: Box<[bool]>,
|
||||
}
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
use ty::Ty;
|
||||
impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
|
||||
match t.kind() {
|
||||
ty::Param(param_ty) => {
|
||||
self.arg_is_constrained[param_ty.index as usize] = true;
|
||||
}
|
||||
ty::Projection(_) => return ControlFlow::Continue(()),
|
||||
_ => (),
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
|
||||
debug!("r={:?}", r.kind());
|
||||
if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
|
||||
self.arg_is_constrained[region.index as usize] = true;
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstrainedCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
regions: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for ConstrainedCollector {
|
||||
impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
match ty.kind {
|
||||
hir::TyKind::Path(
|
||||
@ -1850,6 +1882,56 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<
|
||||
// (defined above)
|
||||
}
|
||||
|
||||
hir::TyKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
|
||||
)) => {
|
||||
// If this is a top level type alias attempt to "look through" it to see if the args
|
||||
// are constrained, instead of assuming they are and inserting all the lifetimes.
|
||||
// This is necessary for the following case:
|
||||
// ```
|
||||
// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
|
||||
// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
|
||||
// ```
|
||||
// If we considered `'a` constrained then it would become late bound causing an error
|
||||
// during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
|
||||
// but appears in the output type `<() as Trait<'a>>::Assoc`.
|
||||
|
||||
let generics = self.tcx.generics_of(alias_def);
|
||||
let mut walker = ConstrainedCollectorPostAstConv {
|
||||
arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
|
||||
};
|
||||
walker.visit_ty(self.tcx.type_of(alias_def));
|
||||
|
||||
match segments.last() {
|
||||
Some(hir::PathSegment { args: Some(args), .. }) => {
|
||||
let tcx = self.tcx;
|
||||
for constrained_arg in
|
||||
args.args.iter().enumerate().flat_map(|(n, arg)| {
|
||||
match walker.arg_is_constrained.get(n) {
|
||||
Some(true) => Some(arg),
|
||||
Some(false) => None,
|
||||
None => {
|
||||
tcx.sess.delay_span_bug(
|
||||
*span,
|
||||
format!(
|
||||
"Incorrect generic arg count for alias {:?}",
|
||||
alias_def
|
||||
),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
self.visit_generic_arg(constrained_arg);
|
||||
}
|
||||
}
|
||||
Some(_) => (),
|
||||
None => bug!("Path with no segments or self type"),
|
||||
}
|
||||
}
|
||||
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
|
||||
// consider only the lifetimes on the final
|
||||
// segment; I am not sure it's even currently
|
||||
|
@ -1,18 +0,0 @@
|
||||
error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
|
||||
--> $DIR/issue-47511.rs:8:15
|
||||
|
|
||||
LL | fn f(_: X) -> X {
|
||||
| ^
|
||||
|
|
||||
= note: lifetimes appearing in an associated or opaque type are not considered constrained
|
||||
= note: consider introducing a named lifetime parameter
|
||||
|
||||
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
|
||||
--> $DIR/issue-47511.rs:12:23
|
||||
|
|
||||
LL | fn g<'a>(_: X<'a>) -> X<'a> {
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0581`.
|
@ -0,0 +1,24 @@
|
||||
// check-pass
|
||||
|
||||
trait Gats<'a> {
|
||||
type Assoc;
|
||||
type Assoc2;
|
||||
}
|
||||
|
||||
trait Trait: for<'a> Gats<'a> {
|
||||
fn foo<'a>(_: &mut <Self as Gats<'a>>::Assoc) -> <Self as Gats<'a>>::Assoc2;
|
||||
}
|
||||
|
||||
impl<'a> Gats<'a> for () {
|
||||
type Assoc = &'a u32;
|
||||
type Assoc2 = ();
|
||||
}
|
||||
|
||||
type GatsAssoc<'a, T> = <T as Gats<'a>>::Assoc;
|
||||
type GatsAssoc2<'a, T> = <T as Gats<'a>>::Assoc2;
|
||||
|
||||
impl Trait for () {
|
||||
fn foo<'a>(_: &mut GatsAssoc<'a, Self>) -> GatsAssoc2<'a, Self> {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,9 +1,4 @@
|
||||
// check-fail
|
||||
// known-bug: #47511
|
||||
|
||||
// Regression test for #47511: anonymous lifetimes can appear
|
||||
// unconstrained in a return type, but only if they appear just once
|
||||
// in the input, as the input to a projection.
|
||||
// check-pass
|
||||
|
||||
fn f(_: X) -> X {
|
||||
unimplemented!()
|
12
src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs
Normal file
12
src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// ensures that we don't ICE when there are too many args supplied to the alias.
|
||||
|
||||
trait Trait<'a> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
type Alias<'a, T> = <T as Trait<'a>>::Assoc;
|
||||
|
||||
fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
|
||||
//~^ error: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
|
||||
|
||||
fn main() {}
|
17
src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr
Normal file
17
src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0107]: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
|
||||
--> $DIR/mismatched_arg_count.rs:9:29
|
||||
|
|
||||
LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
|
||||
| ^^^^^ -- help: remove this lifetime argument
|
||||
| |
|
||||
| expected 1 lifetime argument
|
||||
|
|
||||
note: type alias defined here, with 1 lifetime parameter: `'a`
|
||||
--> $DIR/mismatched_arg_count.rs:7:6
|
||||
|
|
||||
LL | type Alias<'a, T> = <T as Trait<'a>>::Assoc;
|
||||
| ^^^^^ --
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0107`.
|
Loading…
x
Reference in New Issue
Block a user