]> git.lizzy.rs Git - rust.git/commitdiff
fixyfixfix
authorBoxy <supbscripter@gmail.com>
Sun, 6 Nov 2022 13:39:13 +0000 (13:39 +0000)
committerBoxy <supbscripter@gmail.com>
Sun, 6 Nov 2022 13:39:18 +0000 (13:39 +0000)
compiler/rustc_hir_analysis/src/collect/lifetimes.rs
src/test/ui/issues/issue-47511.rs [deleted file]
src/test/ui/issues/issue-47511.stderr [deleted file]
src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/issue-47511.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs [new file with mode: 0644]
src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr [new file with mode: 0644]

index 3d07f3fbc674dbb3d32ba541a95cf0c5c0309698..b9583bd2244b9b4d1fb742f00a377cf6bc2a84ab 100644 (file)
@@ -18,7 +18,7 @@
 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 visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                     // (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
diff --git a/src/test/ui/issues/issue-47511.rs b/src/test/ui/issues/issue-47511.rs
deleted file mode 100644 (file)
index eb4860e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-fn f(_: X) -> X {
-    unimplemented!()
-}
-
-fn g<'a>(_: X<'a>) -> X<'a> {
-    unimplemented!()
-}
-
-type X<'a> = <&'a () as Trait>::Value;
-
-trait Trait {
-    type Value;
-}
-
-impl<'a> Trait for &'a () {
-    type Value = ();
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-47511.stderr b/src/test/ui/issues/issue-47511.stderr
deleted file mode 100644 (file)
index 9998ee0..0000000
+++ /dev/null
@@ -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`.
diff --git a/src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs b/src/test/ui/late-bound-lifetimes/downgraded_to_early_through_alias.rs
new file mode 100644 (file)
index 0000000..e56a342
--- /dev/null
@@ -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() {}
diff --git a/src/test/ui/late-bound-lifetimes/issue-47511.rs b/src/test/ui/late-bound-lifetimes/issue-47511.rs
new file mode 100644 (file)
index 0000000..7894435
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+
+fn f(_: X) -> X {
+    unimplemented!()
+}
+
+fn g<'a>(_: X<'a>) -> X<'a> {
+    unimplemented!()
+}
+
+type X<'a> = <&'a () as Trait>::Value;
+
+trait Trait {
+    type Value;
+}
+
+impl<'a> Trait for &'a () {
+    type Value = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs b/src/test/ui/late-bound-lifetimes/mismatched_arg_count.rs
new file mode 100644 (file)
index 0000000..0b331e2
--- /dev/null
@@ -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() {}
diff --git a/src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr b/src/test/ui/late-bound-lifetimes/mismatched_arg_count.stderr
new file mode 100644 (file)
index 0000000..3704d9b
--- /dev/null
@@ -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`.