Propagate Expectation around binop typeck code to construct more precise trait obligations for binops.
This commit is contained in:
parent
8c1cc82a82
commit
e5bb7d80d6
@ -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>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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 {
|
||||
|
@ -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 (
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
|
46
src/test/ui/generic-associated-types/missing-bounds.fixed
Normal file
46
src/test/ui/generic-associated-types/missing-bounds.fixed
Normal file
@ -0,0 +1,46 @@
|
||||
// run-rustfix
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
struct A<B>(B);
|
||||
|
||||
impl<B> Add for A<B> where B: Add + Add<Output = B> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
A(self.0 + rhs.0) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
struct C<B>(B);
|
||||
|
||||
impl<B: Add + Add<Output = B>> Add for C<B> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self(self.0 + rhs.0) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
struct D<B>(B);
|
||||
|
||||
impl<B: std::ops::Add<Output=B>> Add for D<B> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B`
|
||||
}
|
||||
}
|
||||
|
||||
struct E<B>(B);
|
||||
|
||||
impl<B: Add + Add<Output = B>> Add for E<B> where B: Add<Output = B> {
|
||||
//~^ ERROR equality constraints are not yet supported in `where` clauses
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
Self(self.0 + rhs.0) //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
struct A<B>(B);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/missing-bounds.rs:35:33
|
||||
--> $DIR/missing-bounds.rs:37:33
|
||||
|
|
||||
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
|
||||
@ -11,7 +11,7 @@ LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/missing-bounds.rs:9:11
|
||||
--> $DIR/missing-bounds.rs:11:11
|
||||
|
|
||||
LL | impl<B> Add for A<B> where B: Add {
|
||||
| - this type parameter
|
||||
@ -24,7 +24,7 @@ LL | A(self.0 + rhs.0)
|
||||
= note: expected type parameter `B`
|
||||
found associated type `<B as Add>::Output`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/missing-bounds.rs:3:8
|
||||
--> $DIR/missing-bounds.rs:5:8
|
||||
|
|
||||
LL | struct A<B>(B);
|
||||
| ^
|
||||
@ -34,7 +34,7 @@ LL | impl<B> Add for A<B> where B: Add + Add<Output = B> {
|
||||
| +++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/missing-bounds.rs:19:14
|
||||
--> $DIR/missing-bounds.rs:21:14
|
||||
|
|
||||
LL | impl<B: Add> Add for C<B> {
|
||||
| - this type parameter
|
||||
@ -47,7 +47,7 @@ LL | Self(self.0 + rhs.0)
|
||||
= note: expected type parameter `B`
|
||||
found associated type `<B as Add>::Output`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/missing-bounds.rs:13:8
|
||||
--> $DIR/missing-bounds.rs:15:8
|
||||
|
|
||||
LL | struct C<B>(B);
|
||||
| ^
|
||||
@ -57,7 +57,7 @@ LL | impl<B: Add + Add<Output = B>> Add for C<B> {
|
||||
| +++++++++++++++++
|
||||
|
||||
error[E0369]: cannot add `B` to `B`
|
||||
--> $DIR/missing-bounds.rs:29:21
|
||||
--> $DIR/missing-bounds.rs:31:21
|
||||
|
|
||||
LL | Self(self.0 + rhs.0)
|
||||
| ------ ^ ----- B
|
||||
@ -66,11 +66,11 @@ LL | Self(self.0 + rhs.0)
|
||||
|
|
||||
help: consider restricting type parameter `B`
|
||||
|
|
||||
LL | impl<B: std::ops::Add> Add for D<B> {
|
||||
| +++++++++++++++
|
||||
LL | impl<B: std::ops::Add<Output=B>> Add for D<B> {
|
||||
| +++++++++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/missing-bounds.rs:40:14
|
||||
--> $DIR/missing-bounds.rs:42:14
|
||||
|
|
||||
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
|
||||
| - this type parameter
|
||||
@ -83,7 +83,7 @@ LL | Self(self.0 + rhs.0)
|
||||
= note: expected type parameter `B`
|
||||
found associated type `<B as Add>::Output`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/missing-bounds.rs:33:8
|
||||
--> $DIR/missing-bounds.rs:35:8
|
||||
|
|
||||
LL | struct E<B>(B);
|
||||
| ^
|
||||
|
@ -8,8 +8,8 @@ LL | n + 10
|
||||
|
|
||||
help: consider restricting type parameter `N`
|
||||
|
|
||||
LL | fn add_ten<N: std::ops::Add<i32>>(n: N) -> N {
|
||||
| ++++++++++++++++++++
|
||||
LL | fn add_ten<N: std::ops::Add<i32><Output=N>>(n: N) -> N {
|
||||
| ++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user