Provide associated type information in method chains

When encountering an unmet obligation that affects a method chain, like
in iterator chains where one of the links has the wrong associated
type, we point at every method call and mention their evaluated
associated type at that point to give context to the user of where
expectations diverged from the code as written.

```
note: the expression is of type `Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/invalid-iterator-chain.rs:12:18: 12:21]>`
  --> $DIR/invalid-iterator-chain.rs:12:14
   |
LL |         vec![0, 1]
   |         ---------- this expression has type `Vec<{integer}>`
LL |             .iter()
   |              ------ associated type `std::iter::Iterator::Item` is `&{integer}` here
LL |             .map(|x| { x; })
   |              ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here
```
This commit is contained in:
Michael Goulet 2022-12-06 17:34:24 +00:00 committed by Esteban Küber
parent d137783642
commit bc60d50eaa
6 changed files with 413 additions and 34 deletions

View File

@ -536,7 +536,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|err| {
self.note_obligation_cause_code(
err,
&predicate,
predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
@ -1586,7 +1586,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
self.note_obligation_cause_code(
&mut diag,
&error.obligation.predicate,
error.obligation.predicate,
error.obligation.param_env,
code,
&mut vec![],
@ -2601,7 +2601,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(
err,
&obligation.predicate,
obligation.predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],

View File

@ -1,8 +1,9 @@
// ignore-tidy-filelength
use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
use crate::traits::NormalizeExt;
use crate::traits::{NormalizeExt, ObligationCtxt};
use hir::def::CtorOf;
use hir::HirId;
@ -22,16 +23,18 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
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,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitable, TypeckResults,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
use std::ops::Deref;
use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
@ -292,13 +295,13 @@ pub trait TypeErrCtxtExt<'tcx> {
fn note_obligation_cause_code<T>(
&self,
err: &mut Diagnostic,
predicate: &T,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display + ToPredicate<'tcx>;
T: ToPredicate<'tcx>;
/// Suggest to await before try: future? => future.await?
fn suggest_await_before_try(
@ -2336,7 +2339,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
debug!(?next_code);
self.note_obligation_cause_code(
err,
&obligation.predicate,
obligation.predicate,
obligation.param_env,
next_code.unwrap(),
&mut Vec::new(),
@ -2347,15 +2350,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn note_obligation_cause_code<T>(
&self,
err: &mut Diagnostic,
predicate: &T,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
T: fmt::Display + ToPredicate<'tcx>,
T: ToPredicate<'tcx>,
{
let tcx = self.tcx;
let predicate = predicate.to_predicate(tcx);
match *cause_code {
ObligationCauseCode::ExprAssignable
| ObligationCauseCode::MatchExpressionArm { .. }
@ -2689,7 +2693,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
parent_predicate,
param_env,
&data.parent_code,
obligated_types,
@ -2700,7 +2704,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
parent_predicate,
param_env,
cause_code.peel_derives(),
obligated_types,
@ -2809,7 +2813,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
parent_predicate,
param_env,
&data.parent_code,
obligated_types,
@ -2824,7 +2828,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
&parent_predicate,
parent_predicate,
param_env,
&data.parent_code,
obligated_types,
@ -2838,16 +2842,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ref parent_code,
} => {
let hir = self.tcx.hir();
if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
hir.find(arg_hir_id)
{
if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) {
let parent_id = hir.get_parent_item(arg_hir_id);
let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
Some(t) if t.hir_owner == parent_id => t,
_ => self.tcx.typeck(parent_id.def_id),
};
if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
let expr = expr.peel_blocks();
let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
let ty =
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
let span = expr.span;
if Some(span) != err.span.primary_span() {
err.span_label(
@ -2860,6 +2864,163 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
}
let span = expr.span;
let mut multi_span: MultiSpan = match expr.kind {
hir::ExprKind::MethodCall(_, _, _, span) => span.into(),
_ => span.into(),
};
// FIXME: visit the ty to see if there's any closure involved, and if there is,
// check whether its evaluated return type is the same as the one corresponding
// to an associated type (as seen from `trait_pred`) in the predicate. Like in
// trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
let mut type_diffs = vec![];
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
&& let Some(pred) = predicates.predicates.get(*idx)
&& let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder()
{
let mut c = CollectAllMismatches {
infcx: self.infcx,
param_env: param_env,
errors: vec![],
};
if let ty::PredicateKind::Clause(ty::Clause::Trait(
predicate
)) = predicate.kind().skip_binder()
{
if let Ok(_) = c.relate(trait_pred, predicate) {
type_diffs = c.errors;
}
}
}
let point_at_chain = |expr: &hir::Expr<'_>| {
let mut expr = expr;
let mut prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
);
let outer_ty = prev_ty;
let mut assoc_seen = 0;
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) =
expr.kind
{
// Point at every method call in the chain with the resulting type.
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
// ^^^^^^ ^^^^^^^^^^^
expr = rcvr_expr;
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
for diff in &type_diffs {
let Sorts(expected_found) = diff else { continue; };
let ty::Projection(proj) = expected_found.expected.kind() else { continue; };
assoc_seen += 1;
let origin = TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
};
let trait_def_id = proj.trait_def_id(self.tcx);
// Make `Self` be equivalent to the type of the call chain
// expression we're looking at now, so that we can tell what
// for example `Iterator::Item` is at this point in the chain.
let substs =
InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
ty::GenericParamDefKind::Type { .. } => {
if param.index == 0 {
return prev_ty.into();
}
}
ty::GenericParamDefKind::Lifetime
| ty::GenericParamDefKind::Const { .. } => {}
}
self.var_for_def(span, param)
});
// This will hold the resolved type of the associated type, if the
// current expression implements the trait that associated type is
// in. For example, this would be what `Iterator::Item` is here.
let ty_var = self.infcx.next_ty_var(origin);
// This corresponds to `<ExprTy as Iterator>::Item = _`.
let trait_ref = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::Clause::Projection(ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
substs,
item_def_id: proj.item_def_id,
},
term: ty_var.into(),
}),
));
// Add `<ExprTy as Iterator>::Item = _` obligation.
ocx.register_obligation(Obligation::misc(
self.tcx,
span,
expr.hir_id,
param_env,
trait_ref,
));
if ocx.select_where_possible().is_empty() {
// `ty_var` now holds the type that `Item` is for `ExprTy`.
let assoc = self.tcx.def_path_str(proj.item_def_id);
multi_span.push_span_label(
span,
&format!(
"associated type `{assoc}` is `{}` here",
self.resolve_vars_if_possible(ty_var),
),
);
} else {
// `<ExprTy as Iterator>` didn't select, so likely we've
// reached the end of the iterator chain, like the originating
// `Vec<_>`.
multi_span.push_span_label(
span,
format!("this call has type `{prev_ty}`"),
);
}
}
prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
);
}
// We want the type before deref coercions, otherwise we talk about `&[_]`
// instead of `Vec<_>`.
if let Some(ty) = typeck_results.expr_ty_opt(expr) {
let ty = self.resolve_vars_if_possible(ty);
// Point at the root expression
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
// ^^^^^^^^^^^^^
multi_span.push_span_label(
expr.span,
format!("this expression has type `{ty}`"),
);
};
if assoc_seen > 0 {
// Only show this if it is not a "trivial" expression (not a method
// chain) and there are associated types to talk about.
err.span_note(
multi_span,
format!("the expression is of type `{outer_ty}`"),
);
}
};
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
&& let Some(binding_expr) = local.init
{
// If the expression we're calling on is a binding, we want to point at the
// `let` when talking about the type. Otherwise we'll point at every part
// of the method chain with the type.
point_at_chain(binding_expr);
} else {
point_at_chain(expr);
}
}
if let Some(Node::Expr(hir::Expr {
kind:
hir::ExprKind::Call(hir::Expr { span, .. }, _)
@ -2888,9 +3049,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
"the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \
corresponding trait's {kind}",
predicate, item_name,
"the requirement `{predicate}` appears on the `impl`'s {kind} \
`{item_name}` but not on the corresponding trait's {kind}",
);
let sp = self
.tcx
@ -2900,7 +3060,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut assoc_span: MultiSpan = sp.into();
assoc_span.push_span_label(
sp,
format!("this trait's {kind} doesn't have the requirement `{}`", predicate),
format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
);
if let Some(ident) = self
.tcx
@ -3286,3 +3446,72 @@ impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
self.tcx
}
}
pub struct CollectAllMismatches<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
pub errors: Vec<TypeError<'tcx>>,
}
impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
fn tag(&self) -> &'static str {
"CollectAllMismatches"
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn intercrate(&self) -> bool {
false
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
fn a_is_expected(&self) -> bool {
true
} // irrelevant
fn mark_ambiguous(&mut self) {
bug!()
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
_: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
self.relate(a, b)
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
_b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
Ok(a)
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
if a == b || matches!(a.kind(), ty::Infer(_)) || matches!(b.kind(), ty::Infer(_)) {
return Ok(a);
}
relate::super_relate_tys(self, a, b).or_else(|e| {
self.errors.push(e);
Ok(a)
})
}
fn consts(
&mut self,
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
if a == b {
return Ok(a);
}
relate::super_relate_consts(self, a, b) // could do something similar here for constants!
}
fn binders<T: Relate<'tcx>>(
&mut self,
a: ty::Binder<'tcx, T>,
b: ty::Binder<'tcx, T>,
) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
}

View File

@ -22,6 +22,14 @@ LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_rece
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: the expression is of type `Map<std::slice::Iter<'_, (_, _, _)>, [closure@$DIR/issue-34334.rs:5:47: 5:82]>`
--> $DIR/issue-34334.rs:5:43
|
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
| -- ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here
| | |
| | associated type `std::iter::Iterator::Item` is `&(_, _, _)` here
| this expression has type `Vec<(_, _, _)>`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|

View File

@ -8,6 +8,13 @@ LL | let x2: Vec<f64> = x1.into_iter().collect();
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: the expression is of type `std::slice::Iter<'_, f64>`
--> $DIR/issue-66923-show-error-for-correct-call.rs:8:27
|
LL | let x2: Vec<f64> = x1.into_iter().collect();
| -- ^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `&f64` here
| |
| this expression has type `&[f64]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
@ -24,6 +31,13 @@ LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: the expression is of type `std::slice::Iter<'_, f64>`
--> $DIR/issue-66923-show-error-for-correct-call.rs:12:17
|
LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
| -- ^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `&f64` here
| |
| this expression has type `&[f64]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|

View File

@ -0,0 +1,17 @@
fn main() {
let scores = vec![(0, 0)]
.iter()
.map(|(a, b)| {
a + b;
});
println!("{}", scores.sum::<i32>()); //~ ERROR E0277
println!(
"{}",
vec![0, 1] //~ ERROR E0277
.iter()
.map(|x| { x; })
.sum::<i32>(),
);
println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); //~ ERROR E0277
println!("{}", vec![(), ()].iter().sum::<i32>()); //~ ERROR E0277
}

View File

@ -0,0 +1,111 @@
error[E0277]: the trait bound `i32: Sum<()>` is not satisfied
--> $DIR/invalid-iterator-chain.rs:7:20
|
LL | println!("{}", scores.sum::<i32>());
| ^^^^^^ --- required by a bound introduced by this call
| |
| the trait `Sum<()>` is not implemented for `i32`
|
= help: the following other types implement trait `Sum<A>`:
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the expression is of type `Map<std::slice::Iter<'_, ({integer}, {integer})>, [closure@$DIR/invalid-iterator-chain.rs:4:14: 4:22]>`
--> $DIR/invalid-iterator-chain.rs:7:20
|
LL | let scores = vec![(0, 0)]
| ------------ this expression has type `Vec<({integer}, {integer})>`
LL | .iter()
| ------ associated type `std::iter::Iterator::Item` is `&({integer}, {integer})` here
LL | .map(|(a, b)| {
| __________-
LL | | a + b;
LL | | });
| |__________- associated type `std::iter::Iterator::Item` is `()` here
LL | println!("{}", scores.sum::<i32>());
| ^^^^^^
note: required by a bound in `std::iter::Iterator::sum`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
LL | S: Sum<Self::Item>,
| ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`
error[E0277]: the trait bound `i32: Sum<()>` is not satisfied
--> $DIR/invalid-iterator-chain.rs:10:9
|
LL | / vec![0, 1]
LL | | .iter()
LL | | .map(|x| { x; })
| |____________________________^ the trait `Sum<()>` is not implemented for `i32`
LL | .sum::<i32>(),
| --- required by a bound introduced by this call
|
= help: the following other types implement trait `Sum<A>`:
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the expression is of type `Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/invalid-iterator-chain.rs:12:18: 12:21]>`
--> $DIR/invalid-iterator-chain.rs:12:14
|
LL | vec![0, 1]
| ---------- this expression has type `Vec<{integer}>`
LL | .iter()
| ------ associated type `std::iter::Iterator::Item` is `&{integer}` here
LL | .map(|x| { x; })
| ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here
note: required by a bound in `std::iter::Iterator::sum`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
LL | S: Sum<Self::Item>,
| ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`
error[E0277]: the trait bound `i32: Sum<()>` is not satisfied
--> $DIR/invalid-iterator-chain.rs:15:20
|
LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
| |
| the trait `Sum<()>` is not implemented for `i32`
|
= help: the following other types implement trait `Sum<A>`:
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the expression is of type `Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/invalid-iterator-chain.rs:15:42: 15:45]>`
--> $DIR/invalid-iterator-chain.rs:15:38
|
LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
| ---------- ------ ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here
| | |
| | associated type `std::iter::Iterator::Item` is `&{integer}` here
| this expression has type `Vec<{integer}>`
note: required by a bound in `std::iter::Iterator::sum`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
LL | S: Sum<Self::Item>,
| ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`
error[E0277]: the trait bound `i32: Sum<&()>` is not satisfied
--> $DIR/invalid-iterator-chain.rs:16:20
|
LL | println!("{}", vec![(), ()].iter().sum::<i32>());
| ^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
| |
| the trait `Sum<&()>` is not implemented for `i32`
|
= help: the following other types implement trait `Sum<A>`:
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the expression is of type `std::slice::Iter<'_, ()>`
--> $DIR/invalid-iterator-chain.rs:16:33
|
LL | println!("{}", vec![(), ()].iter().sum::<i32>());
| ------------ ^^^^^^ associated type `std::iter::Iterator::Item` is `&()` here
| |
| this expression has type `Vec<()>`
note: required by a bound in `std::iter::Iterator::sum`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
LL | S: Sum<Self::Item>,
| ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.