about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2021-02-12 22:44:43 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2021-02-13 19:30:07 +0000
commitdfee89f75545b4fadc559eee324afc8bb0bdc1be (patch)
tree486a81d0f0a7613b0c65f3fac233b4d0ed00bcf3
parent79f6f11816cbef2bba6f5da6d4a4f0aa10535b88 (diff)
downloadrust-dfee89f75545b4fadc559eee324afc8bb0bdc1be.tar.gz
rust-dfee89f75545b4fadc559eee324afc8bb0bdc1be.zip
Make ProjectionTy::trait_ref truncate substs again
Also make sure that type arguments of associated types are printed in
some error messages.
-rw-r--r--compiler/rustc_middle/src/ty/error.rs40
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs16
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs37
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs3
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs7
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs14
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs7
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs33
-rw-r--r--src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs17
-rw-r--r--src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr27
-rw-r--r--src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs35
-rw-r--r--src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr29
12 files changed, 216 insertions, 49 deletions
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 1669c59d7f1..ff955244924 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,5 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, DiagnosticBuilder};
@@ -400,14 +401,22 @@ impl<'tcx> TyCtxt<'tcx> {
                         {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
-                            let trait_ref = proj.trait_ref(self);
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
                             let path =
                                 self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
                             let item_name = self.item_name(proj.item_def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
                             let path = if path.ends_with('>') {
-                                format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
                             } else {
-                                format!("{}<{} = {}>", path, item_name, p)
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
                             };
                             note = !suggest_constraining_type_param(
                                 self,
@@ -556,7 +565,7 @@ impl<T> Trait<T> for X {
         ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
-        let trait_ref = proj_ty.trait_ref(self);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
         if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
             if let Some(hir_generics) = item.generics() {
                 // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
@@ -590,6 +599,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             pred.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         ) {
@@ -607,6 +617,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             param.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         );
@@ -692,6 +703,7 @@ impl<T> Trait<T> for X {
                 db,
                 self.def_span(def_id),
                 &assoc,
+                proj_ty.trait_ref_and_own_substs(self).1,
                 values.found,
                 &msg,
             ) {
@@ -856,6 +868,7 @@ fn foo(&self) -> Self::T { String::new() }
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -865,7 +878,12 @@ fn foo(&self) -> Self::T { String::new() }
                 // Relate the type param against `T` in `<A as T>::Foo`.
                 ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
                     && self.constrain_associated_type_structured_suggestion(
-                        db, ptr.span, assoc, ty, msg,
+                        db,
+                        ptr.span,
+                        assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
                     )
             }
             _ => false,
@@ -879,6 +897,7 @@ fn foo(&self) -> Self::T { String::new() }
         db: &mut DiagnosticBuilder<'_>,
         span: Span,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -890,11 +909,20 @@ fn foo(&self) -> Self::T { String::new() }
                 let span = Span::new(pos, pos, span.ctxt());
                 (span, format!(", {} = {}", assoc.ident, ty))
             } else {
-                (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
             };
             db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
         }
         false
     }
+
+    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+        let mut item_args = String::new();
+        FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.");
+        item_args
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index babab005edb..b7f62437fa5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
         self.skip_binder().projection_ty.item_def_id
     }
 
+    /// Returns the `DefId` of the trait of the associated item being projected.
     #[inline]
-    pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        self.skip_binder().projection_ty.trait_def_id(tcx)
+    }
+
+    #[inline]
+    pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
+        self.map_bound(|predicate| predicate.projection_ty.self_ty())
+    }
+
+    /// Get the [PolyTraitRef] required for this projection to be well formed.
+    /// Note that for generic associated types the predicates of the associated
+    /// type also need to be checked.
+    #[inline]
+    pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
         // Note: unlike with `TraitRef::to_poly_trait_ref()`,
         // `self.0.trait_ref` is permitted to have escaping regions.
         // This is because here `self` has a `Binder` and so does our
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 388a5767870..754108ea3c5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -17,7 +17,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi;
 use std::borrow::Cow;
@@ -1112,20 +1112,35 @@ pub struct ProjectionTy<'tcx> {
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        tcx.associated_item(self.item_def_id).container.id()
+    }
+
+    /// Extracts the underlying trait reference and own substs from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+    pub fn trait_ref_and_own_substs(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let trait_generics = tcx.generics_of(def_id);
+        (
+            ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+            &self.substs[trait_generics.count()..],
+        )
+    }
+
     /// Extracts the underlying trait reference from this projection.
     /// For example, if this is a projection of `<T as Iterator>::Item`,
     /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the substs for generic associated types
+    /// consider calling [Self::trait_ref_and_own_substs] to get those
+    /// as well.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        // FIXME: This method probably shouldn't exist at all, since it's not
-        // clear what this method really intends to do. Be careful when
-        // using this method since the resulting TraitRef additionally
-        // contains the substs for the assoc_item, which strictly speaking
-        // is not correct
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
-        // Include substitutions for generic arguments of associated types
-        let assoc_item = tcx.associated_item(self.item_def_id);
-        let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
-        ty::TraitRef { def_id, substs: substs_assoc_item }
+        let def_id = self.trait_def_id(tcx);
+        ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 3233d1e048b..e9aaa652564 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
             }
             ty::PredicateKind::Projection(data) => {
-                let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.skip_binder().self_ty();
+                let self_ty = data.projection_ty.self_ty();
                 let ty = data.ty;
                 if predicate.references_error() {
                     return;
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 7d3589c4b6b..fdf5f697e61 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
-        let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+        let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
         chalk_solve::rust_ir::AliasEqBound {
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
-            parameters: self.projection_ty.substs[trait_ref.substs.len()..]
-                .iter()
-                .map(|arg| arg.lower_into(interner))
-                .collect(),
+            parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
             value: self.ty.lower_into(interner),
         }
     }
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index f34aaec10a9..431e6d70ff3 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
 
         // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur if there is a trait-reference
+        // infer the kind. This can occur when we elaborate a predicate
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
         let expected_kind = self
@@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!("deduce_sig_from_projection({:?})", projection);
 
-        let trait_ref = projection.to_poly_trait_ref(tcx);
+        let trait_def_id = projection.trait_def_id(tcx);
 
-        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
+        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
-        let is_gen = gen_trait == trait_ref.def_id();
+        let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
             return None;
@@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let input_tys = if is_fn {
-            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
             debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
@@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Check that this is a projection from the `Future` trait.
-        let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+        let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
         let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
-        if trait_ref.def_id != future_trait {
+        if trait_def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
             return None;
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index bc1a07801ae..75c73e0b67c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .filter_map(move |obligation| {
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
+                    ty::PredicateKind::Projection(data) => Some((
+                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
+                        obligation,
+                    )),
                     ty::PredicateKind::Trait(data, _) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d49c7cae822..14d019fa01a 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -24,6 +24,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::Obligation;
 
 use std::cmp::Ordering;
+use std::iter;
 
 use super::probe::Mode;
 use super::{CandidateSource, MethodError, NoMatchData};
@@ -649,21 +650,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ty::PredicateKind::Projection(pred) => {
                                 let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
-                                let trait_ref =
-                                    pred.skip_binder().projection_ty.trait_ref(self.tcx);
-                                let assoc = self
-                                    .tcx
-                                    .associated_item(pred.skip_binder().projection_ty.item_def_id);
-                                let ty = pred.skip_binder().ty;
-                                let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
-                                let quiet = format!(
-                                    "<_ as {}>::{} = {}",
-                                    trait_ref.print_only_trait_path(),
-                                    assoc.ident,
-                                    ty
+                                let projection_ty = pred.skip_binder().projection_ty;
+
+                                let substs_with_infer_self = tcx.mk_substs(
+                                    iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+                                        .chain(projection_ty.substs.iter().skip(1)),
                                 );
-                                bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
-                                Some((obligation, trait_ref.self_ty()))
+
+                                let quiet_projection_ty = ty::ProjectionTy {
+                                    substs: substs_with_infer_self,
+                                    item_def_id: projection_ty.item_def_id,
+                                };
+
+                                let ty = pred.skip_binder().ty;
+
+                                let obligation = format!("{} = {}", projection_ty, ty);
+                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+
+                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                                Some((obligation, projection_ty.self_ty()))
                             }
                             ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.trait_ref;
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
new file mode 100644
index 00000000000..36db3d1bb9e
--- /dev/null
+++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs
@@ -0,0 +1,17 @@
+// Test that correct syntax is used in suggestion to constrain associated type
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<T>;
+}
+
+fn f<T: X>(a: T::Y<i32>) {
+    //~^ HELP consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+    //~| SUGGESTION Y<i32> = Vec<i32>>
+    let b: Vec<i32> = a;
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
new file mode 100644
index 00000000000..ecf559d9e94
--- /dev/null
+++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr
@@ -0,0 +1,27 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/constraint-assoc-type-suggestion.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0308]: mismatched types
+  --> $DIR/constraint-assoc-type-suggestion.rs:13:23
+   |
+LL |     let b: Vec<i32> = a;
+   |            --------   ^ expected struct `Vec`, found associated type
+   |            |
+   |            expected due to this
+   |
+   = note:       expected struct `Vec<i32>`
+           found associated type `<T as X>::Y<i32>`
+help: consider constraining the associated type `<T as X>::Y<i32>` to `Vec<i32>`
+   |
+LL | fn f<T: X<Y<i32> = Vec<i32>>>(a: T::Y<i32>) {
+   |          ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
new file mode 100644
index 00000000000..2de4c7b8492
--- /dev/null
+++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs
@@ -0,0 +1,35 @@
+// Test that the predicate printed in an unresolved method error prints the
+// generics for a generic associated type.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+//~| NOTE `#[warn(incomplete_features)]` on by default
+//~| NOTE see issue #44265
+
+trait X {
+    type Y<T>;
+}
+
+trait M {
+    fn f(&self) {}
+}
+
+impl<T: X<Y<i32> = i32>> M for T {}
+
+struct S;
+//~^ NOTE method `f` not found for this
+//~| NOTE doesn't satisfy `<S as X>::Y<i32> = i32`
+//~| NOTE doesn't satisfy `S: M`
+
+impl X for S {
+    type Y<T> = bool;
+}
+
+fn f(a: S) {
+    a.f();
+    //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied
+    //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds
+    //~| NOTE the following trait bounds were not satisfied:
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
new file mode 100644
index 00000000000..c94155d13c3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
@@ -0,0 +1,29 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
+  --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7
+   |
+LL | struct S;
+   | ---------
+   | |
+   | method `f` not found for this
+   | doesn't satisfy `<S as X>::Y<i32> = i32`
+   | doesn't satisfy `S: M`
+...
+LL |     a.f();
+   |       ^ method cannot be called on `S` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `<S as X>::Y<i32> = i32`
+           which is required by `S: M`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0599`.