Rollup merge of #67460 - estebank:named-lts, r=nikomatsakis
Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes Fix #66406, fix #72106. ``` error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | fn get_relation(&self) -> To; | ----------------------------- expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` --> $DIR/trait-param-without-lifetime-constraint.rs:10:31 | LL | fn get_relation(&self) -> To; | ^^ consider borrowing this type parameter in the trait ``` r? @nikomatsakis
This commit is contained in:
commit
81207802a0
|
@ -193,9 +193,18 @@ impl Diagnostic {
|
|||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self {
|
||||
let expected_label = format!("expected {}", expected_label);
|
||||
|
||||
let found_label = format!("found {}", found_label);
|
||||
let expected_label = expected_label.to_string();
|
||||
let expected_label = if expected_label.is_empty() {
|
||||
"expected".to_string()
|
||||
} else {
|
||||
format!("expected {}", expected_label)
|
||||
};
|
||||
let found_label = found_label.to_string();
|
||||
let found_label = if found_label.is_empty() {
|
||||
"found".to_string()
|
||||
} else {
|
||||
format!("found {}", found_label)
|
||||
};
|
||||
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
|
||||
(expected_label.len() - found_label.len(), 0)
|
||||
} else {
|
||||
|
|
|
@ -987,12 +987,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn push_ty_ref<'tcx>(
|
||||
r: &ty::Region<'tcx>,
|
||||
region: &ty::Region<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
s: &mut DiagnosticStyledString,
|
||||
) {
|
||||
let mut r = r.to_string();
|
||||
let mut r = region.to_string();
|
||||
if r == "'_" {
|
||||
r.clear();
|
||||
} else {
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::{Subtype, ValuePairs};
|
||||
use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
|
||||
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
|
||||
|
@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
var_origin.span(),
|
||||
sub_expected_found.expected,
|
||||
sub_expected_found.found,
|
||||
self.tcx().def_span(*trait_item_def_id),
|
||||
*trait_item_def_id,
|
||||
);
|
||||
return Some(ErrorReported);
|
||||
}
|
||||
|
@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
|
||||
fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
|
||||
let tcx = self.tcx();
|
||||
let trait_sp = self.tcx().def_span(trait_def_id);
|
||||
let mut err = self
|
||||
.tcx()
|
||||
.sess
|
||||
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
|
||||
err.span_label(sp, &format!("found `{:?}`", found));
|
||||
err.span_label(trait_sp, &format!("expected `{:?}`", expected));
|
||||
|
||||
// Get the span of all the used type parameters in the method.
|
||||
let assoc_item = self.tcx().associated_item(trait_def_id);
|
||||
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
let hir = self.tcx().hir();
|
||||
if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id))
|
||||
{
|
||||
if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
|
||||
visitor.visit_fn_decl(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut type_param_span: MultiSpan =
|
||||
visitor.types.iter().cloned().collect::<Vec<_>>().into();
|
||||
for &span in &visitor.types {
|
||||
type_param_span.push_span_label(
|
||||
span,
|
||||
"consider borrowing this type parameter in the trait".to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((expected, found)) = tcx
|
||||
.infer_ctxt()
|
||||
.enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
|
||||
{
|
||||
// Highlighted the differences when showing the "expected/found" note.
|
||||
err.note_expected_found(&"", expected, &"", found);
|
||||
} else {
|
||||
// This fallback shouldn't be necessary, but let's keep it in just in case.
|
||||
err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found));
|
||||
err.span_label(sp, &format!("found {:?}", found));
|
||||
err.span_label(impl_sp, &format!("expected {:?}", expected));
|
||||
}
|
||||
err.span_help(
|
||||
type_param_span,
|
||||
"the lifetime requirements from the `impl` do not correspond to the requirements in \
|
||||
the `trait`",
|
||||
);
|
||||
if visitor.types.is_empty() {
|
||||
err.help(
|
||||
"verify the lifetime relationships in the `trait` and `impl` between the `self` \
|
||||
argument, the other inputs and its output",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeParamSpanVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
types: Vec<Span>,
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||
type Map = rustc_middle::hir::map::Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
|
||||
hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
|
||||
match arg.kind {
|
||||
hir::TyKind::Rptr(_, ref mut_ty) => {
|
||||
// We don't want to suggest looking into borrowing `&T` or `&Self`.
|
||||
hir::intravisit::walk_ty(self, mut_ty.ty);
|
||||
return;
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
|
||||
[segment]
|
||||
if segment
|
||||
.res
|
||||
.map(|res| match res {
|
||||
Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false) =>
|
||||
{
|
||||
self.types.push(path.span);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
hir::intravisit::walk_ty(self, arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,17 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl-2.rs:8:5
|
||||
|
|
||||
LL | fn deref(&self) -> &dyn Trait {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
|
||||
|
|
||||
::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
|
||||
|
|
||||
LL | fn deref(&self) -> &Self::Target;
|
||||
| --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
|
||||
| --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
|
||||
|
|
||||
= note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
|
||||
found `fn(&Struct) -> &dyn Trait`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl.rs:9:5
|
||||
|
|
||||
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
|
||||
| ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
|
||||
| ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
...
|
||||
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
found `fn(&i32, &u32, &u32) -> &u32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/mismatched_trait_impl.rs:9:5
|
||||
|
|
||||
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
|
||||
| ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
|
||||
| ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
...
|
||||
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
|
||||
found `fn(&i32, &u32, &u32) -> &u32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/mismatched_trait_impl.rs:10:9
|
||||
|
|
|
@ -2,13 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
|
|||
--> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
|
||||
|
|
||||
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
|
||||
| ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32
|
||||
| ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
|
||||
...
|
||||
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
|
||||
|
|
||||
= note: expected `fn(&i32, &'a i32) -> &'a i32`
|
||||
found `fn(&i32, &i32) -> &i32`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ValueRef<'a> {
|
||||
Null,
|
||||
Integer(i64),
|
||||
Real(f64),
|
||||
Text(&'a [u8]),
|
||||
Blob(&'a [u8]),
|
||||
}
|
||||
|
||||
impl<'a> ValueRef<'a> {
|
||||
pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> {
|
||||
match *self {
|
||||
ValueRef::Text(t) => {
|
||||
std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x))
|
||||
}
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum FromSqlError {
|
||||
InvalidType
|
||||
}
|
||||
|
||||
impl fmt::Display for FromSqlError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "InvalidType")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for FromSqlError {}
|
||||
|
||||
pub type FromSqlResult<T, K> = Result<(T, K), FromSqlError>;
|
||||
|
||||
pub trait FromSql: Sized {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
}
|
||||
|
||||
impl FromSql for &str {
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
value.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("{}", "Hello World");
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/self-without-lifetime-constraint.rs:45:5
|
||||
|
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
| -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
|
||||
...
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>`
|
||||
|
|
||||
= note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
|
||||
found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>`
|
||||
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
--> $DIR/self-without-lifetime-constraint.rs:41:60
|
||||
|
|
||||
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
|
||||
| ^^^^ consider borrowing this type parameter in the trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
struct Article {
|
||||
proof_reader: ProofReader,
|
||||
}
|
||||
|
||||
struct ProofReader {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub trait HaveRelationship<To> {
|
||||
fn get_relation(&self) -> To;
|
||||
}
|
||||
|
||||
impl HaveRelationship<&ProofReader> for Article {
|
||||
fn get_relation(&self) -> &ProofReader {
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
&self.proof_reader
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,19 @@
|
|||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/trait-param-without-lifetime-constraint.rs:14:5
|
||||
|
|
||||
LL | fn get_relation(&self) -> To;
|
||||
| ----------------------------- expected `fn(&Article) -> &ProofReader`
|
||||
...
|
||||
LL | fn get_relation(&self) -> &ProofReader {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
|
||||
|
|
||||
= note: expected `fn(&Article) -> &ProofReader`
|
||||
found `fn(&Article) -> &ProofReader`
|
||||
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
--> $DIR/trait-param-without-lifetime-constraint.rs:10:31
|
||||
|
|
||||
LL | fn get_relation(&self) -> To;
|
||||
| ^^ consider borrowing this type parameter in the trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue