]> git.lizzy.rs Git - rust.git/commitdiff
don't normalize wf predicates
authorlcnr <rust@lcnr.de>
Wed, 13 Jul 2022 17:42:08 +0000 (19:42 +0200)
committerlcnr <rust@lcnr.de>
Tue, 9 Aug 2022 10:54:32 +0000 (12:54 +0200)
this allows us to soundly use unnormalized projections for wf

27 files changed:
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_typeck/src/check/compare_method.rs
src/test/ui/associated-types/issue-59324.rs
src/test/ui/associated-types/issue-59324.stderr
src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr [deleted file]
src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr [new file with mode: 0644]
src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
src/test/ui/generic-associated-types/bugs/issue-87748.rs [deleted file]
src/test/ui/generic-associated-types/bugs/issue-87748.stderr [deleted file]
src/test/ui/generic-associated-types/issue-87748.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr

index 167960918308cd365c50894a3db07acc040415e4..9fab7ad914a847118c4d0a4abf067707141d4f06 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -109,23 +109,11 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
                 self.add_outlives(r1_vid, r2_vid);
             }
 
-            GenericArgKind::Type(mut t1) => {
+            GenericArgKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
 
-                // Placeholder regions need to be converted now because it may
-                // create new region variables, which can't be done later when
-                // verifying these bounds.
-                if t1.has_placeholders() {
-                    t1 = tcx.fold_regions(t1, |r, _| match *r {
-                        ty::RePlaceholder(placeholder) => {
-                            self.constraints.placeholder_region(self.infcx, placeholder)
-                        }
-                        _ => r,
-                    });
-                }
-
                 TypeOutlives::new(
                     &mut *self,
                     tcx,
@@ -143,6 +131,25 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
         }
     }
 
+    /// Placeholder regions need to be converted eagerly because it may
+    /// create new region variables, which we must not do when verifying
+    /// our region bounds.
+    ///
+    /// FIXME: This should get removed once higher ranked region obligations
+    /// are dealt with during trait solving.
+    fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+        if value.has_placeholders() {
+            self.tcx.fold_regions(value, |r, _| match *r {
+                ty::RePlaceholder(placeholder) => {
+                    self.constraints.placeholder_region(self.infcx, placeholder)
+                }
+                _ => r,
+            })
+        } else {
+            value
+        }
+    }
+
     fn verify_to_type_test(
         &mut self,
         generic_kind: GenericKind<'tcx>,
@@ -150,7 +157,6 @@ fn verify_to_type_test(
         verify_bound: VerifyBound<'tcx>,
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
-
         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
     }
 
@@ -198,6 +204,8 @@ fn push_verify(
         a: ty::Region<'tcx>,
         bound: VerifyBound<'tcx>,
     ) {
+        let kind = self.replace_placeholders_with_nll(kind);
+        let bound = self.replace_placeholders_with_nll(bound);
         let type_test = self.verify_to_type_test(kind, a, bound);
         self.add_type_test(type_test);
     }
index cc0318ede54a0e98858df911cd48a6134d811656..74655369faf0388d5872ffae944e3895202f3d4a 100644 (file)
@@ -242,10 +242,9 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                // We only add implied bounds for the normalized type as the unnormalized
-                // type may not actually get checked by the caller.
-                //
-                // Can otherwise be unsound, see #91068.
+                // We add implied bounds from both the unnormalized and normalized ty.
+                // See issue #87748
+                let constraints_implied1 = self.add_implied_bounds(ty);
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
@@ -273,9 +272,10 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
                 // }
                 // ```
                 // Both &Self::Bar and &() are WF
-                let constraints_implied = self.add_implied_bounds(norm_ty);
+                let constraints_implied2 =
+                    if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
                 normalized_inputs_and_output.push(norm_ty);
-                constraints1.into_iter().chain(constraints_implied)
+                constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
             })
             .collect();
 
index d32b1edcd8fd75b7e942d5d4e833f04eea9e4c3c..7bf7f7357bf4f57c5d4f6d8cb71b447f2434aba2 100644 (file)
@@ -1448,9 +1448,14 @@ fn check_terminator(
                     ))
                 });
                 debug!(?sig);
-                let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+                // IMPORTANT: We have to prove well formed for the function signature before
+                // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+                // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+                //
+                // Normalization results in a well formed type if the input is well formed, so we
+                // don't have to check it twice.
+                //
+                // See #91068 for an example.
                 self.prove_predicates(
                     sig.inputs_and_output
                         .iter()
@@ -1458,6 +1463,8 @@ fn check_terminator(
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
+                let sig = self.normalize(sig, term_location);
+                self.check_call_dest(body, term, &sig, *destination, target, term_location);
 
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
index 0d4472a1cfd9c11944821f2992dca524e9458c39..780e6ead10efa8e6062e8d0fa185735a54db43f1 100644 (file)
@@ -187,7 +187,7 @@ pub enum GenericKind<'tcx> {
 /// }
 /// ```
 /// This is described with an `AnyRegion('a, 'b)` node.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
 pub enum VerifyBound<'tcx> {
     /// See [`VerifyIfEq`] docs
     IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
index 79309097e785b2920d9c44f852b67c1bcdeb339b..a7833ab64310fc29513aac6f9c7eb015cc1f29ba 100644 (file)
@@ -594,6 +594,29 @@ pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
         }
         self
     }
+
+    /// Whether this projection can be soundly normalized.
+    ///
+    /// Wf predicates must not be normalized, as normalization
+    /// can remove required bounds which would cause us to
+    /// unsoundly accept some programs. See #91068.
+    #[inline]
+    pub fn allow_normalization(self) -> bool {
+        match self.kind().skip_binder() {
+            PredicateKind::WellFormed(_) => false,
+            PredicateKind::Trait(_)
+            | PredicateKind::RegionOutlives(_)
+            | PredicateKind::TypeOutlives(_)
+            | PredicateKind::Projection(_)
+            | PredicateKind::ObjectSafe(_)
+            | PredicateKind::ClosureKind(_, _, _)
+            | PredicateKind::Subtype(_)
+            | PredicateKind::Coerce(_)
+            | PredicateKind::ConstEvaluatable(_)
+            | PredicateKind::ConstEquate(_, _)
+            | PredicateKind::TypeWellFormedFromEnv(_) => true,
+        }
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
index adf47ece69d99aa37d981c504bdf4058832712ce..74625cc7bb750ad97814aebc77b965bd2893e43b 100644 (file)
@@ -619,6 +619,15 @@ fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
             constant.eval(self.selcx.tcx(), self.param_env)
         }
     }
+
+    #[inline]
+    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.super_fold_with(self)
+        } else {
+            p
+        }
+    }
 }
 
 pub struct BoundVarReplacer<'me, 'tcx> {
index 449d7a7b47b1fcd82042d7156c0cb876c0ab25a2..38b3a4b7253daf8f72b61da07842d07bc55a3b32 100644 (file)
@@ -351,4 +351,16 @@ fn try_fold_mir_const(
             mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
         })
     }
+
+    #[inline]
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.try_super_fold_with(self)
+        } else {
+            Ok(p)
+        }
+    }
 }
index 666498403c4f7c57acdbe420f4a0eddaf53bb1a8..15a995ae59a8bfd8966a1c7a0bce88d9b2cc1459 100644 (file)
@@ -264,8 +264,13 @@ fn compare_predicate_entailment<'tcx>(
 
         let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+        // Next, add all inputs and output as well-formed tys. Importantly,
+        // we have to do this before normalization, since the normalized ty may
+        // not contain the input parameters. See issue #87748.
+        wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
-        // Add the resulting inputs and output as well-formed.
+        // We also have to add the normalized trait signature
+        // as we don't normalize during implied bounds computation.
         wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
 
index 162f9e00edd81a369cfe739569cd28af4c81afe1..9e68e9e77515bc6633b0ad3e8a603f98c765d587 100644 (file)
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
-    //~^ the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
index a84b599b52b68d2c28913dfdb70c5d08f8714bf6..dd5ec7175b5f1aa47ac07db08a3786875027cf4b 100644 (file)
@@ -20,7 +20,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |
+LL | |     ) -> Self::AssocType;
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -34,6 +34,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
+LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -50,10 +51,10 @@ LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:19:10
+  --> $DIR/issue-59324.rs:16:8
    |
-LL |     ) -> Self::AssocType;
-   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL |     fn get_service(
+   |        ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
index 5a92bcd37b6eea8e7f96dee471cc3e2167a3980e..5d924555625cdc408a9a4495e9aba100b62fdc53 100644 (file)
@@ -1,4 +1,4 @@
-// check-pass
+// check-fail
 
 trait Trait {
     type Type;
@@ -17,6 +17,7 @@ fn f<'a, 'b>(_: <&'a &'b () as Trait>::Type)
 
 fn g<'a, 'b>() {
     f::<'a, 'b>(());
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr
new file mode 100644 (file)
index 0000000..0c3df04
--- /dev/null
@@ -0,0 +1,17 @@
+error: lifetime may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-2.rs:19:5
+   |
+LL | fn g<'a, 'b>() {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     f::<'a, 'b>(());
+   |     ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a function pointer to `f`
+   = note: the function `f` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
index dc25ac086137a9ba13e715f4688286ba40e04f84..888f74cf6b33745b76e8351f0e1edc03a9de69be 100644 (file)
@@ -1,6 +1,4 @@
-// check-fail
-// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a
-// source of unsoundness.
+// check-pass
 
 pub trait Yokeable<'a>: 'static {
     type Output: 'a;
@@ -17,7 +15,6 @@ pub trait ZeroCopyFrom<C: ?Sized>: for<'a> Yokeable<'a> {
 
 impl<T> ZeroCopyFrom<[T]> for &'static [T] {
     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-        //~^ the parameter
         cart
     }
 }
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
deleted file mode 100644 (file)
index 95cf4fb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
-   |
-LL |     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] {
-   |       +++++++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs
new file mode 100644 (file)
index 0000000..1285925
--- /dev/null
@@ -0,0 +1,24 @@
+// A regression test for #98543
+
+trait Trait {
+    type Type;
+}
+
+impl<T> Trait for T {
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
+where
+    &'a &'b (): Trait, // <- adding this bound is the change from #91068
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
new file mode 100644 (file)
index 0000000..fcbaa91
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10
+   |
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs
new file mode 100644 (file)
index 0000000..2a9a6a8
--- /dev/null
@@ -0,0 +1,23 @@
+trait Trait<'a>: 'a {
+    type Type;
+}
+
+// if the `T: 'a` bound gets implied we would probably get ub here again
+impl<'a, T> Trait<'a> for T {
+    //~^ ERROR the parameter type `T` may not live long enough
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'b () as Trait<'a>>::Type) -> &'a str
+where
+    &'b (): Trait<'a>,
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
new file mode 100644 (file)
index 0000000..458756a
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13
+   |
+LL | impl<'a, T> Trait<'a> for T {
+   |             ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18
+   |
+LL | trait Trait<'a>: 'a {
+   |                  ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+   |           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
index 04b6f4dd84e2e92cfadbb794e1f01ec73c6cc4ab..d58d25036c5bb78898587ca026e1d0a44bee1552 100644 (file)
@@ -1,6 +1,6 @@
 // check-fail
-// See issue #91068. Types in the substs of an associated type can't be implied
-// to be WF, since they don't actually have to be constructed.
+// See issue #91068. We check that the unnormalized associated types in
+// function signatures are implied
 
 trait Trait {
     type Type;
@@ -12,12 +12,12 @@ impl<T> Trait for T {
 
 fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
     s
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {
     let x = String::from("Hello World!");
     let y = f(&x, ());
     drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
     println!("{}", y);
 }
index 8096f08385c8c67b7a6c7fe27962b7e8260a184a..e35f46e4439a90b1c9e94ac8396b8a2077b9851b 100644 (file)
@@ -1,14 +1,14 @@
-error: lifetime may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10
    |
-LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-LL |     s
-   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
-   |
-   = help: consider adding the following bound: `'b: 'a`
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
deleted file mode 100644 (file)
index a3d00ee..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// check-fail
-// known-bug: #87748
-
-// This should pass, but unnormalized input args aren't treated as implied.
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
-    type Assoc<'a, 'b> where 'b: 'a;
-    fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct Foo;
-
-impl MyTrait for Foo {
-    type Assoc<'a, 'b> = u32 where 'b: 'a;
-
-    fn do_sth(_: u32) {}
-    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
-    // fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-
-fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
deleted file mode 100644 (file)
index ac197df..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-note: but lifetime parameter must outlive the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/generic-associated-types/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs
new file mode 100644 (file)
index 0000000..1a1ab9b
--- /dev/null
@@ -0,0 +1,23 @@
+// Checks that we properly add implied bounds from unnormalized projections in
+// inputs when typechecking functions.
+
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+    type Assoc<'a, 'b> where 'b: 'a;
+    fn do_sth(arg: Self::Assoc<'_, '_>);
+    fn do_sth2(arg: Self::Assoc<'_, '_>) {}
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+    type Assoc<'a, 'b> = u32 where 'b: 'a;
+
+    fn do_sth(_: u32) {}
+    fn do_sth2(_: Self::Assoc<'static, 'static>) {}
+}
+
+fn main() {}
index 172bf218c0d4cd7244dcdbbeb4a3cd3f0a62ccd2..de9348f5397099bf5267a8426b28d084fd7bb47e 100644 (file)
@@ -7,7 +7,6 @@ trait SomeTrait<'a> {
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
     //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
-    //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
index ecca4b999e7e8c1c04bb230261d1c50a8646e545..6a948a116e03bf3bf7477cb94b5060e05bebe960 100644 (file)
@@ -9,17 +9,6 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
    |                 +++++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
-  --> $DIR/issue-85455.rs:8:14
-   |
-LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
-   |                 +++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
index c4db6fc97dc32468798403b8f7505acb3cac0e44..05e2ea047f65af722c5f6d59cde97252dde32839 100644 (file)
@@ -30,4 +30,5 @@ fn main() {
     let _x = <fn(&())>::make_f();
     //~^ ERROR implementation of `Y` is not general enough
     //~| ERROR implementation of `Y` is not general enough
+    //~| ERROR implementation of `Y` is not general enough
 }
index 51adfca3e79f488dc0dc753a4ed6e20cd356b36f..8c47379886d2a8a873b79f0246502b2d055007d5 100644 (file)
@@ -16,5 +16,14 @@ LL |     let _x = <fn(&())>::make_f();
    = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
-error: aborting due to 2 previous errors
+error: implementation of `Y` is not general enough
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+   |
+   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: aborting due to 3 previous errors