mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Point at fewer methods in the chain, only those that change the E type
This commit is contained in:
parent
6c3879d1f1
commit
53817963ed
@ -1049,39 +1049,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
let mut prev_ty = self.resolve_vars_if_possible(
|
let mut prev_ty = self.resolve_vars_if_possible(
|
||||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||||
);
|
);
|
||||||
let mut annotate_expr = |span: Span, prev_ty: Ty<'tcx>, self_ty: Ty<'tcx>| -> bool {
|
|
||||||
// We always look at the `E` type, because that's the only one affected by `?`. If the
|
// We always look at the `E` type, because that's the only one affected by `?`. If the
|
||||||
// incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
|
// incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
|
||||||
// expression, after the `?` has "unwrapped" the `T`.
|
// expression, after the `?` has "unwrapped" the `T`.
|
||||||
|
let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {
|
||||||
let ty::Adt(def, args) = prev_ty.kind() else {
|
let ty::Adt(def, args) = prev_ty.kind() else {
|
||||||
return false;
|
return None;
|
||||||
};
|
};
|
||||||
let Some(arg) = args.get(1) else {
|
let Some(arg) = args.get(1) else {
|
||||||
return false;
|
return None;
|
||||||
};
|
};
|
||||||
if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {
|
if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
let can = if self
|
Some(arg.as_type()?)
|
||||||
.infcx
|
|
||||||
.type_implements_trait(
|
|
||||||
self.tcx.get_diagnostic_item(sym::From).unwrap(),
|
|
||||||
[self_ty.into(), *arg],
|
|
||||||
obligation.param_env,
|
|
||||||
)
|
|
||||||
.must_apply_modulo_regions()
|
|
||||||
{
|
|
||||||
"can"
|
|
||||||
} else {
|
|
||||||
"can't"
|
|
||||||
};
|
|
||||||
err.span_label(
|
|
||||||
span,
|
|
||||||
format!("this {can} be annotated with `?` because it has type `{prev_ty}`"),
|
|
||||||
);
|
|
||||||
true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut chain = vec![];
|
||||||
|
|
||||||
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
|
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
|
||||||
let mut expr = expr;
|
let mut expr = expr;
|
||||||
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
|
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
|
||||||
@ -1089,9 +1075,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
// let foo = bar.iter().map(mapper)?;
|
// let foo = bar.iter().map(mapper)?;
|
||||||
// ------ -----------
|
// ------ -----------
|
||||||
expr = rcvr_expr;
|
expr = rcvr_expr;
|
||||||
if !annotate_expr(span, prev_ty, self_ty) {
|
chain.push((span, prev_ty));
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_ty = self.resolve_vars_if_possible(
|
prev_ty = self.resolve_vars_if_possible(
|
||||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||||
@ -1121,7 +1105,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
prev_ty = self.resolve_vars_if_possible(
|
prev_ty = self.resolve_vars_if_possible(
|
||||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||||
);
|
);
|
||||||
annotate_expr(expr.span, prev_ty, self_ty);
|
chain.push((expr.span, prev_ty));
|
||||||
|
|
||||||
|
let mut prev = None;
|
||||||
|
for (span, err_ty) in chain.into_iter().rev() {
|
||||||
|
let err_ty = get_e_type(err_ty);
|
||||||
|
let err_ty = match (err_ty, prev) {
|
||||||
|
(Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {
|
||||||
|
err_ty
|
||||||
|
}
|
||||||
|
(Some(err_ty), None) => err_ty,
|
||||||
|
_ => {
|
||||||
|
prev = err_ty;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if self
|
||||||
|
.infcx
|
||||||
|
.type_implements_trait(
|
||||||
|
self.tcx.get_diagnostic_item(sym::From).unwrap(),
|
||||||
|
[self_ty, err_ty],
|
||||||
|
obligation.param_env,
|
||||||
|
)
|
||||||
|
.must_apply_modulo_regions()
|
||||||
|
{
|
||||||
|
err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
|
||||||
|
} else {
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
prev = Some(err_ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_const_param_not_wf(
|
fn report_const_param_not_wf(
|
||||||
|
@ -3,18 +3,17 @@ fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this
|
|||||||
let x = test
|
let x = test
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| { //~ NOTE this can be annotated with `?` because it has type `Result<&str, &str>`
|
.ok_or_else(|| { //~ NOTE this has type `Result<_, &str>`
|
||||||
"Couldn't split the test string"
|
"Couldn't split the test string"
|
||||||
});
|
});
|
||||||
let one = x
|
let one = x
|
||||||
.map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), &str>`
|
.map(|s| ())
|
||||||
.map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<(), ()>`
|
.map_err(|_| ()) //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
.map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String`
|
.map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String`
|
||||||
//~^ NOTE in this expansion of desugaring of operator `?`
|
//~^ NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE this can't be annotated with `?` because it has type `Result<&str, ()>`
|
|
||||||
//~| NOTE the trait `From<()>` is not implemented for `String`
|
//~| NOTE the trait `From<()>` is not implemented for `String`
|
||||||
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
//~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
|
//~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
|
||||||
@ -22,15 +21,15 @@ fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this
|
fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this
|
||||||
let x = foo(); //~ NOTE this can be annotated with `?` because it has type `Result<String, String>`
|
let x = foo(); //~ NOTE this has type `Result<_, String>`
|
||||||
let one = x
|
let one = x
|
||||||
.map(|s| ()) //~ NOTE this can be annotated with `?` because it has type `Result<(), String>`
|
.map(|s| ())
|
||||||
.map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String`
|
.map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String`
|
||||||
//~^ NOTE in this expansion of desugaring of operator `?`
|
//~^ NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE in this expansion of desugaring of operator `?`
|
//~| NOTE in this expansion of desugaring of operator `?`
|
||||||
//~| NOTE this can't be annotated with `?` because it has type `Result<(), ()>`
|
//~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
//~| NOTE the trait `From<()>` is not implemented for `String`
|
//~| NOTE the trait `From<()>` is not implemented for `String`
|
||||||
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
//~| NOTE required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
|
//~| NOTE required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
|
||||||
@ -42,7 +41,7 @@ fn baz() -> Result<String, String> { //~ NOTE expected `String` because of this
|
|||||||
let one = test
|
let one = test
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<&str, ()>`
|
.ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
"Couldn't split the test string";
|
"Couldn't split the test string";
|
||||||
})?;
|
})?;
|
||||||
//~^ ERROR `?` couldn't convert the error to `String`
|
//~^ ERROR `?` couldn't convert the error to `String`
|
||||||
|
@ -8,16 +8,12 @@ LL | .ok_or_else(|| {
|
|||||||
| __________-
|
| __________-
|
||||||
LL | | "Couldn't split the test string"
|
LL | | "Couldn't split the test string"
|
||||||
LL | | });
|
LL | | });
|
||||||
| |__________- this can be annotated with `?` because it has type `Result<&str, &str>`
|
| |__________- this has type `Result<_, &str>`
|
||||||
LL | let one = x
|
...
|
||||||
LL | .map(|s| ())
|
|
||||||
| ----------- this can be annotated with `?` because it has type `Result<(), &str>`
|
|
||||||
LL | .map_err(|_| ())
|
LL | .map_err(|_| ())
|
||||||
| --------------- this can't be annotated with `?` because it has type `Result<(), ()>`
|
| --------------- this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
LL | .map(|()| "")?;
|
LL | .map(|()| "")?;
|
||||||
| ------------^ the trait `From<()>` is not implemented for `String`
|
| ^ the trait `From<()>` is not implemented for `String`
|
||||||
| |
|
|
||||||
| this can't be annotated with `?` because it has type `Result<&str, ()>`
|
|
||||||
|
|
|
|
||||||
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
= help: the following other types implement trait `From<T>`:
|
= help: the following other types implement trait `From<T>`:
|
||||||
@ -30,19 +26,17 @@ LL | .map(|()| "")?;
|
|||||||
= note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
|
= note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
|
||||||
|
|
||||||
error[E0277]: `?` couldn't convert the error to `String`
|
error[E0277]: `?` couldn't convert the error to `String`
|
||||||
--> $DIR/question-mark-result-err-mismatch.rs:28:25
|
--> $DIR/question-mark-result-err-mismatch.rs:27:25
|
||||||
|
|
|
|
||||||
LL | fn bar() -> Result<(), String> {
|
LL | fn bar() -> Result<(), String> {
|
||||||
| ------------------ expected `String` because of this
|
| ------------------ expected `String` because of this
|
||||||
LL | let x = foo();
|
LL | let x = foo();
|
||||||
| ----- this can be annotated with `?` because it has type `Result<String, String>`
|
| ----- this has type `Result<_, String>`
|
||||||
LL | let one = x
|
...
|
||||||
LL | .map(|s| ())
|
|
||||||
| ----------- this can be annotated with `?` because it has type `Result<(), String>`
|
|
||||||
LL | .map_err(|_| ())?;
|
LL | .map_err(|_| ())?;
|
||||||
| ---------------^ the trait `From<()>` is not implemented for `String`
|
| ---------------^ the trait `From<()>` is not implemented for `String`
|
||||||
| |
|
| |
|
||||||
| this can't be annotated with `?` because it has type `Result<(), ()>`
|
| this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
|
|
|
|
||||||
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
= help: the following other types implement trait `From<T>`:
|
= help: the following other types implement trait `From<T>`:
|
||||||
@ -55,7 +49,7 @@ LL | .map_err(|_| ())?;
|
|||||||
= note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
|
= note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>`
|
||||||
|
|
||||||
error[E0277]: `?` couldn't convert the error to `String`
|
error[E0277]: `?` couldn't convert the error to `String`
|
||||||
--> $DIR/question-mark-result-err-mismatch.rs:47:11
|
--> $DIR/question-mark-result-err-mismatch.rs:46:11
|
||||||
|
|
|
|
||||||
LL | fn baz() -> Result<String, String> {
|
LL | fn baz() -> Result<String, String> {
|
||||||
| ---------------------- expected `String` because of this
|
| ---------------------- expected `String` because of this
|
||||||
@ -66,7 +60,7 @@ LL | | "Couldn't split the test string";
|
|||||||
LL | | })?;
|
LL | | })?;
|
||||||
| | -^ the trait `From<()>` is not implemented for `String`
|
| | -^ the trait `From<()>` is not implemented for `String`
|
||||||
| |__________|
|
| |__________|
|
||||||
| this can't be annotated with `?` because it has type `Result<&str, ()>`
|
| this can't be annotated with `?` because it has type `Result<_, ()>`
|
||||||
|
|
|
|
||||||
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
= help: the following other types implement trait `From<T>`:
|
= help: the following other types implement trait `From<T>`:
|
||||||
|
Loading…
Reference in New Issue
Block a user