about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs16
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs10
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs1
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs30
-rw-r--r--compiler/rustc_typeck/src/check/op.rs85
8 files changed, 134 insertions, 30 deletions
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index d8cc7d3feb0..945cdfbb0e9 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -12,7 +12,7 @@ pub mod util;
 use crate::infer::canonical::Canonical;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, AdtKind, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -414,6 +414,7 @@ pub enum ObligationCauseCode<'tcx> {
     BinOp {
         rhs_span: Option<Span>,
         is_lit: bool,
+        output_pred: Option<Predicate<'tcx>>,
     },
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f0acb02933a..3536d946db2 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1033,6 +1033,24 @@ impl<'tcx> Predicate<'tcx> {
         }
     }
 
+    pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> {
+        let predicate = self.kind();
+        match predicate.skip_binder() {
+            PredicateKind::Projection(t) => Some(predicate.rebind(t)),
+            PredicateKind::Trait(..)
+            | PredicateKind::Subtype(..)
+            | PredicateKind::Coerce(..)
+            | PredicateKind::RegionOutlives(..)
+            | PredicateKind::WellFormed(..)
+            | PredicateKind::ObjectSafe(..)
+            | PredicateKind::ClosureKind(..)
+            | PredicateKind::TypeOutlives(..)
+            | PredicateKind::ConstEvaluatable(..)
+            | PredicateKind::ConstEquate(..)
+            | PredicateKind::TypeWellFormedFromEnv(..) => None,
+        }
+    }
+
     pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
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 39fce3cf769..c1af1a05972 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -665,6 +665,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             self.suggest_restricting_param_bound(
                                 &mut err,
                                 trait_predicate,
+                                None,
                                 obligation.cause.body_id,
                             );
                         } else if !suggested {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 57d5e5436a6..469436ff0db 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -24,7 +24,8 @@ use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
-    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -172,6 +173,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
+        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
         body_id: hir::HirId,
     );
 
@@ -457,6 +459,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         mut err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
+        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
         body_id: hir::HirId,
     ) {
         let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
@@ -589,9 +592,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
-                    let constraint = with_no_trimmed_paths!(
+                    let mut constraint = with_no_trimmed_paths!(
                         trait_pred.print_modifiers_and_trait_path().to_string()
                     );
+
+                    if let Some(proj_pred) = proj_pred {
+                        let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder();
+                        let item = self.tcx.associated_item(projection_ty.item_def_id);
+                        constraint.push_str(&format!("<{}={}>", item.name, term.to_string()));
+                    }
+
                     if suggest_constraining_type_param(
                         self.tcx,
                         generics,
@@ -2825,7 +2835,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) {
         let rhs_span = match obligation.cause.code() {
-            ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit } if *is_lit => span,
+            ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span,
             _ => return,
         };
         match (
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 2400211394e..b52cb8e99d1 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -282,11 +282,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match expr.kind {
             ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected),
             ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
-            ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs),
+            ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
             ExprKind::Assign(lhs, rhs, span) => {
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
-            ExprKind::AssignOp(op, lhs, rhs) => self.check_binop_assign(expr, op, lhs, rhs),
+            ExprKind::AssignOp(op, lhs, rhs) => {
+                self.check_binop_assign(expr, op, lhs, rhs, expected)
+            }
             ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
             ExprKind::AddrOf(kind, mutbl, oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
@@ -404,14 +406,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
                 hir::UnOp::Not => {
-                    let result = self.check_user_unop(expr, oprnd_t, unop);
+                    let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner);
                     // If it's builtin, we can reuse the type, this helps inference.
                     if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) {
                         oprnd_t = result;
                     }
                 }
                 hir::UnOp::Neg => {
-                    let result = self.check_user_unop(expr, oprnd_t, unop);
+                    let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner);
                     // If it's builtin, we can reuse the type, this helps inference.
                     if !oprnd_t.is_numeric() {
                         oprnd_t = result;
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 42a9a23559c..d33b5b21403 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -413,6 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))),
+                    output_pred: None,
                 },
             ),
             self.param_env,
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index c0b3a23fde4..c09f63f1e8f 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -10,7 +10,7 @@ mod suggest;
 pub use self::suggest::SelfSource;
 pub use self::MethodError::*;
 
-use crate::check::FnCtxt;
+use crate::check::{Expectation, FnCtxt};
 use crate::ObligationCause;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -20,8 +20,10 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
-use rustc_middle::ty::{DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{
+    self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term,
+    ToPredicate, Ty, TypeVisitable,
+};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -318,6 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self_ty: Ty<'tcx>,
         opt_input_type: Option<Ty<'tcx>>,
         opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
+        expected: Expectation<'tcx>,
     ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
     {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
@@ -339,6 +342,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
+        let opt_output_ty =
+            expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
+        let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind(
+            self.tcx,
+            Ident::from_str("Output"),
+            AssocKind::Type,
+            trait_def_id,
+        );
+        let output_pred =
+            opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| {
+                ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate {
+                    projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id },
+                    term: Term::Ty(output_ty),
+                }))
+                .to_predicate(self.tcx)
+            });
+
         (
             traits::Obligation::new(
                 traits::ObligationCause::new(
@@ -348,6 +368,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         rhs_span: opt_input_expr.map(|expr| expr.span),
                         is_lit: opt_input_expr
                             .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+                        output_pred,
                     },
                 ),
                 self.param_env,
@@ -397,6 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self_ty: Ty<'tcx>,
         opt_input_type: Option<Ty<'tcx>>,
         opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
+        expected: Expectation<'tcx>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         let (obligation, substs) = self.obligation_for_op_method(
             span,
@@ -404,6 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self_ty,
             opt_input_type,
             opt_input_expr,
+            expected,
         );
         self.construct_obligation_for_trait(
             span,
@@ -505,6 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+                    output_pred: None,
                 },
             )
         } else {
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 0887c27ea36..d4bb3d43eff 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -2,10 +2,12 @@
 
 use super::method::MethodCallee;
 use super::{has_expected_num_generic_args, FnCtxt};
+use crate::check::Expectation;
 use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
@@ -30,9 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         op: hir::BinOp,
         lhs: &'tcx hir::Expr<'tcx>,
         rhs: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let (lhs_ty, rhs_ty, return_ty) =
-            self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes);
+            self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes, expected);
 
         let ty =
             if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
@@ -50,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Some(rhs_ty),
                         Some(rhs),
                         Op::Binary(op, IsAssign::Yes),
+                        expected,
                     )
                     .is_ok()
                 {
@@ -70,6 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         op: hir::BinOp,
         lhs_expr: &'tcx hir::Expr<'tcx>,
         rhs_expr: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
@@ -94,8 +99,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Otherwise, we always treat operators as if they are
                 // overloaded. This is the way to be most flexible w/r/t
                 // types that get inferred.
-                let (lhs_ty, rhs_ty, return_ty) =
-                    self.check_overloaded_binop(expr, lhs_expr, rhs_expr, op, IsAssign::No);
+                let (lhs_ty, rhs_ty, return_ty) = self.check_overloaded_binop(
+                    expr,
+                    lhs_expr,
+                    rhs_expr,
+                    op,
+                    IsAssign::No,
+                    expected,
+                );
 
                 // Supply type inference hints if relevant. Probably these
                 // hints should be enforced during select as part of the
@@ -176,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         rhs_expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
         is_assign: IsAssign,
+        expected: Expectation<'tcx>,
     ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
         debug!(
             "check_overloaded_binop(expr.hir_id={}, op={:?}, is_assign={:?})",
@@ -222,6 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Some(rhs_ty_var),
             Some(rhs_expr),
             Op::Binary(op, is_assign),
+            expected,
         );
 
         // see `NB` above
@@ -282,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
             Err(errors) => {
                 let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, _use_output) = match is_assign {
+                let (mut err, missing_trait, use_output) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -406,6 +419,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 rhs_expr,
                                 op,
                                 is_assign,
+                                expected,
                             );
                             self.add_type_neq_err_label(
                                 &mut err,
@@ -415,6 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 lhs_expr,
                                 op,
                                 is_assign,
+                                expected,
                             );
                         }
                         self.note_unmet_impls_on_type(&mut err, errors);
@@ -429,6 +444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             Some(rhs_ty),
                             Some(rhs_expr),
                             Op::Binary(op, is_assign),
+                            expected,
                         )
                         .is_ok()
                     {
@@ -490,19 +506,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Some(rhs_ty),
                                 Some(rhs_expr),
                                 Op::Binary(op, is_assign),
+                                expected,
                             )
                             .unwrap_err();
-                        let predicates = errors
-                            .into_iter()
-                            .filter_map(|error| error.obligation.predicate.to_opt_poly_trait_pred())
-                            .collect::<Vec<_>>();
-                        if !predicates.is_empty() {
-                            for pred in predicates {
-                                self.infcx.suggest_restricting_param_bound(
-                                    &mut err,
-                                    pred,
-                                    self.body_id,
-                                );
+                        if !errors.is_empty() {
+                            for error in errors {
+                                if let Some(trait_pred) =
+                                    error.obligation.predicate.to_opt_poly_trait_pred()
+                                {
+                                    let proj_pred = match error.obligation.cause.code() {
+                                        ObligationCauseCode::BinOp {
+                                            output_pred: Some(output_pred),
+                                            ..
+                                        } if use_output => {
+                                            output_pred.to_opt_poly_projection_pred()
+                                        }
+                                        _ => None,
+                                    };
+
+                                    self.infcx.suggest_restricting_param_bound(
+                                        &mut err,
+                                        trait_pred,
+                                        proj_pred,
+                                        self.body_id,
+                                    );
+                                }
                             }
                         } else if *ty != lhs_ty {
                             // When we know that a missing bound is responsible, we don't show
@@ -532,6 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         other_expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
         is_assign: IsAssign,
+        expected: Expectation<'tcx>,
     ) -> bool /* did we suggest to call a function because of missing parentheses? */ {
         err.span_label(span, ty.to_string());
         if let FnDef(def_id, _) = *ty.kind() {
@@ -561,6 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Some(other_ty),
                     Some(other_expr),
                     Op::Binary(op, is_assign),
+                    expected,
                 )
                 .is_ok()
             {
@@ -677,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ex: &'tcx hir::Expr<'tcx>,
         operand_ty: Ty<'tcx>,
         op: hir::UnOp,
+        expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         assert!(op.is_by_value());
-        match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span)) {
+        match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) {
             Ok(method) => {
                 self.write_method_call(ex.hir_id, method);
                 method.sig.output()
@@ -712,6 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.infcx.suggest_restricting_param_bound(
                                 &mut err,
                                 pred,
+                                None,
                                 self.body_id,
                             );
                         }
@@ -772,6 +804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         other_ty: Option<Ty<'tcx>>,
         other_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         op: Op,
+        expected: Expectation<'tcx>,
     ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
         let lang = self.tcx.lang_items();
 
@@ -856,7 +889,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let opname = Ident::with_dummy_span(opname);
         let method = trait_did.and_then(|trait_did| {
-            self.lookup_op_method_in_trait(span, opname, trait_did, lhs_ty, other_ty, other_ty_expr)
+            self.lookup_op_method_in_trait(
+                span,
+                opname,
+                trait_did,
+                lhs_ty,
+                other_ty,
+                other_ty_expr,
+                expected,
+            )
         });
 
         match (method, trait_did) {
@@ -867,8 +908,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             (None, None) => Err(vec![]),
             (None, Some(trait_did)) => {
-                let (obligation, _) =
-                    self.obligation_for_op_method(span, trait_did, lhs_ty, other_ty, other_ty_expr);
+                let (obligation, _) = self.obligation_for_op_method(
+                    span,
+                    trait_did,
+                    lhs_ty,
+                    other_ty,
+                    other_ty_expr,
+                    expected,
+                );
                 let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
                 fulfill.register_predicate_obligation(self, obligation);
                 Err(fulfill.select_where_possible(&self.infcx))