Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
def_id: _,
generic_args,
have_turbofish,
hir_id,
} => {
let generics = self.tcx.generics_of(generics_def_id);
let is_type = term.as_type().is_some();
Expand All @@ -577,7 +578,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn)
== Some(generics_def_id)
{
"Vec<_>".to_string()
if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(hir_id)
&& let hir::ExprKind::Call(expr, _args) = expr.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
&& let Res::Def(DefKind::AssocFn, def_id) = path.res
&& let Some(try_trait) = self.tcx.lang_items().try_trait()
&& try_trait == self.tcx.parent(def_id)
&& let DefKind::Fn | DefKind::AssocFn =
self.tcx.def_kind(body_def_id.to_def_id())
&& let ret = self
.tcx
.fn_sig(body_def_id.to_def_id())
.instantiate_identity()
.skip_binder()
.output()
&& let ty::Adt(adt, _args) = ret.kind()
&& let Some(sym::Option | sym::Result) =
self.tcx.get_diagnostic_name(adt.did())
{
if let Some(sym::Option) = self.tcx.get_diagnostic_name(adt.did()) {
"Option<_>".to_string()
} else {
"Result<_, _>".to_string()
}
} else {
"Vec<_>".to_string()
}
} else {
let mut p = fmt_printer(self, Namespace::TypeNS);
p.comma_sep(generic_args.iter().copied().map(|arg| {
Expand Down Expand Up @@ -710,6 +736,7 @@ enum InferSourceKind<'tcx> {
def_id: DefId,
generic_args: &'tcx [GenericArg<'tcx>],
have_turbofish: bool,
hir_id: HirId,
},
FullyQualifiedMethodCall {
receiver: &'tcx Expr<'tcx>,
Expand Down Expand Up @@ -1188,19 +1215,45 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {

if let Some(ty) = self.opt_node_type(local.hir_id) {
if self.generic_arg_contains_target(ty.into()) {
match local.source {
LocalSource::Normal if local.ty.is_none() => {
self.update_infer_source(InferSource {
span: local.pat.span,
kind: InferSourceKind::LetBinding {
insert_span: local.pat.span.shrink_to_hi(),
pattern_name: local.pat.simple_ident(),
ty,
def_id: None,
},
})
fn get_did(
typeck_results: &TypeckResults<'_>,
expr: &hir::Expr<'_>,
) -> Option<DefId> {
match expr.kind {
hir::ExprKind::Match(expr, _, hir::MatchSource::TryDesugar(_))
if let hir::ExprKind::Call(_, [expr]) = expr.kind =>
{
get_did(typeck_results, expr)
}
hir::ExprKind::Call(base, _args)
if let hir::ExprKind::Path(path) = base.kind
&& let hir::QPath::Resolved(_, path) = path
&& let Res::Def(_, did) = path.res =>
{
Some(did)
}
hir::ExprKind::MethodCall(..)
if let Some(did) =
typeck_results.type_dependent_def_id(expr.hir_id) =>
{
Some(did)
}
_ => None,
}
_ => {}
}

if let LocalSource::Normal = local.source
&& local.ty.is_none()
{
self.update_infer_source(InferSource {
span: local.pat.span,
kind: InferSourceKind::LetBinding {
insert_span: local.pat.span.shrink_to_hi(),
pattern_name: local.pat.simple_ident(),
ty,
def_id: local.init.and_then(|expr| get_did(self.typeck_results, expr)),
},
});
}
}
}
Expand Down Expand Up @@ -1285,6 +1338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
def_id,
generic_args,
have_turbofish,
hir_id: expr.hir_id,
},
});
}
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/inference/question-mark-type-infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ fn g() -> Result<Vec<i32>, ()> {
l.iter().map(f).collect()?
//~^ ERROR type annotations needed
}
fn h() -> Result<(), ()> {
let l = [1, 2, 3, 4];
// The resulting binding doesn't have a type, so we need to guess the `Ok` type too.
let x = l.iter().map(f).collect()?;
//~^ ERROR type annotations needed
Ok(())
}
fn i() -> Result<(), ()> {
let l = [1, 2, 3, 4];
// The resulting binding already has a type, so we don't need to specify the `Ok` type.
let x: Vec<i32> = l.iter().map(f).collect()?;
//~^ ERROR type annotations needed
Ok(())
}

fn main() {
g();
Expand Down
34 changes: 31 additions & 3 deletions tests/ui/inference/question-mark-type-infer.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,37 @@ note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider specifying the generic argument
|
LL | l.iter().map(f).collect::<Vec<_>>()?
| ++++++++++
LL | l.iter().map(f).collect::<Result<_, _>>()?
| ++++++++++++++++

error: aborting due to 1 previous error
error[E0283]: type annotations needed
--> $DIR/question-mark-type-infer.rs:16:29
|
LL | let x = l.iter().map(f).collect()?;
| ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`
|
= note: cannot satisfy `_: FromIterator<Result<i32, ()>>`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider specifying the generic argument
|
LL | let x = l.iter().map(f).collect::<Result<_, _>>()?;
| ++++++++++++++++

error[E0283]: type annotations needed
--> $DIR/question-mark-type-infer.rs:23:39
|
LL | let x: Vec<i32> = l.iter().map(f).collect()?;
| ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`
|
= note: cannot satisfy `_: FromIterator<Result<i32, ()>>`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider specifying the generic argument
|
LL | let x: Vec<i32> = l.iter().map(f).collect::<Result<_, _>>()?;
| ++++++++++++++++

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0283`.
84 changes: 84 additions & 0 deletions tests/ui/inference/question-mark-type-inference-in-chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// #129269
use std::fmt::Display;

#[derive(Debug)]
struct AnotherError;
type Result<T, E = AnotherError> = core::result::Result<T, E>;

#[derive(Debug)]
pub struct Error;

impl From<AnotherError> for Error {
fn from(_: AnotherError) -> Self { Error }
}

impl std::error::Error for Error {}

impl Display for Error {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}

#[derive(Ord, PartialEq, PartialOrd, Eq)]
pub struct Version {}

fn parse(_s: &str) -> std::result::Result<Version, Error> {
todo!()
}

pub fn error1(lines: &[&str]) -> Result<Vec<Version>> {
let mut tags = lines.iter().map(|e| parse(e)).collect()?;
//~^ ERROR: type annotations needed
//~| HELP: consider giving `tags` an explicit type

tags.sort(); //~ NOTE: type must be known at this point

Ok(tags)
}

pub fn error2(lines: &[&str]) -> Result<Vec<Version>> {
let mut tags: Vec<Version> = lines.iter().map(|e| parse(e)).collect()?;
//~^ ERROR: type annotations needed
//~| NOTE: cannot infer type of the type parameter `B`
//~| NOTE: cannot satisfy `_: FromIterator<std::result::Result<Version, Error>>`
//~| NOTE: required by a bound in `collect`
//~| HELP: consider specifying the generic argument
tags.sort();

Ok(tags)
}

pub fn error3(lines: &[&str]) -> Result<Vec<Version>> {
let mut tags = lines.iter().map(|e| parse(e)).collect::<Vec<_>>()?;
//~^ ERROR: the `?` operator can only be applied to values that implement `Try`
//~| NOTE: the `?` operator cannot be applied to type `Vec<std::result::Result<Version, Error>>`
//~| HELP: the nightly-only, unstable trait `Try` is not implemented
//~| NOTE: in this expansion of desugaring of operator `?`
//~| NOTE: in this expansion of desugaring of operator `?`
tags.sort();

Ok(tags)
}

pub fn error4(lines: &[&str]) -> Result<Vec<Version>> {
let mut tags = lines
//~^ NOTE: this expression has type `&[&str]`
.iter()
//~^ NOTE: `Iterator::Item` is `&&str` here
.map(|e| parse(e))
//~^ NOTE: the method call chain might not have had the expected associated types
//~| NOTE: `Iterator::Item` changed to `Result<Version, Error>` here
.collect::<Result<Vec<Version>>>()?;
//~^ ERROR: a value of type `std::result::Result<Vec<Version>, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result<Version, Error>`
//~| NOTE: value of type `std::result::Result<Vec<Version>, AnotherError>` cannot be built from `std::iter::Iterator<Item=std::result::Result<Version, Error>>`
//~| NOTE: required by a bound introduced by this call
//~| HELP: the trait
//~| HELP: for that trait implementation, expected `AnotherError`, found `Error`
//~| NOTE: required by a bound in `collect`
tags.sort();

Ok(tags)
}

fn main() {}
66 changes: 66 additions & 0 deletions tests/ui/inference/question-mark-type-inference-in-chain.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
error[E0282]: type annotations needed
--> $DIR/question-mark-type-inference-in-chain.rs:31:9
|
LL | let mut tags = lines.iter().map(|e| parse(e)).collect()?;
| ^^^^^^^^
...
LL | tags.sort();
| ---- type must be known at this point
|
help: consider giving `tags` an explicit type
|
LL | let mut tags: Vec<_> = lines.iter().map(|e| parse(e)).collect()?;
| ++++++++

error[E0283]: type annotations needed
--> $DIR/question-mark-type-inference-in-chain.rs:41:65
|
LL | let mut tags: Vec<Version> = lines.iter().map(|e| parse(e)).collect()?;
| ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`
|
= note: cannot satisfy `_: FromIterator<std::result::Result<Version, Error>>`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider specifying the generic argument
|
LL | let mut tags: Vec<Version> = lines.iter().map(|e| parse(e)).collect::<Result<_, _>>()?;
| ++++++++++++++++

error[E0277]: the `?` operator can only be applied to values that implement `Try`
--> $DIR/question-mark-type-inference-in-chain.rs:53:20
|
LL | let mut tags = lines.iter().map(|e| parse(e)).collect::<Vec<_>>()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `Vec<std::result::Result<Version, Error>>`
|
= help: the nightly-only, unstable trait `Try` is not implemented for `Vec<std::result::Result<Version, Error>>`

error[E0277]: a value of type `std::result::Result<Vec<Version>, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result<Version, Error>`
--> $DIR/question-mark-type-inference-in-chain.rs:72:20
|
LL | .collect::<Result<Vec<Version>>>()?;
| ------- ^^^^^^^^^^^^^^^^^^^^ value of type `std::result::Result<Vec<Version>, AnotherError>` cannot be built from `std::iter::Iterator<Item=std::result::Result<Version, Error>>`
| |
| required by a bound introduced by this call
|
help: the trait `FromIterator<std::result::Result<_, Error>>` is not implemented for `std::result::Result<Vec<Version>, AnotherError>`
but trait `FromIterator<std::result::Result<_, AnotherError>>` is implemented for it
--> $SRC_DIR/core/src/result.rs:LL:COL
= help: for that trait implementation, expected `AnotherError`, found `Error`
note: the method call chain might not have had the expected associated types
--> $DIR/question-mark-type-inference-in-chain.rs:69:10
|
LL | let mut tags = lines
| ----- this expression has type `&[&str]`
LL |
LL | .iter()
| ------ `Iterator::Item` is `&&str` here
LL |
LL | .map(|e| parse(e))
| ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `Result<Version, Error>` here
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0277, E0282, E0283.
For more information about an error, try `rustc --explain E0277`.
Loading