From 4ee2fcef0c639e69d3ed603480f8dd92755541d0 Mon Sep 17 00:00:00 2001 From: Mathias Blikstad Date: Fri, 17 May 2024 00:28:55 +0100 Subject: [PATCH 1/3] Fix issue #125143 - More than one unnamed lifetimes gave incorrect spans when lookup was done by name (since they both had name "'_"). Use DefId instead to get correct spans. --- compiler/rustc_hir/src/hir.rs | 4 ++++ compiler/rustc_infer/src/infer/error_reporting/mod.rs | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 904abe45a231b..263e84441f46e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -571,6 +571,10 @@ impl<'hir> Generics<'hir> { self.params.iter().find(|¶m| name == param.name.ident().name) } + pub fn get_with_def_id(&self, id: DefId) -> Option<&GenericParam<'hir>> { + self.params.iter().find(|¶m| id.index == param.def_id.local_def_index) + } + /// If there are generic parameters, return where to introduce a new one. pub fn span_for_lifetime_suggestion(&self) -> Option { if let Some(first) = self.params.first() diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d0687dfc6fd25..d3babf7ed1894 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -201,8 +201,10 @@ fn msg_span_from_named_region<'tcx>( match *region { ty::ReEarlyParam(ref br) => { let scope = region.free_region_binding_scope(tcx).expect_local(); - let span = if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + let span = if let Some(param) = tcx + .hir() + .get_generics(scope) + .and_then(|generics| generics.get_with_def_id(br.def_id)) { param.span } else { From c4210bb82231cb65ffaad98deca93f967267474b Mon Sep 17 00:00:00 2001 From: Mathias Blikstad Date: Fri, 17 May 2024 23:33:35 +0100 Subject: [PATCH 2/3] Add UI Test for issue #125143 --- .../unnamed-lifetime-span-mixup-125143.rs | 42 +++++++++++++ .../unnamed-lifetime-span-mixup-125143.stderr | 60 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 tests/ui/inference/unnamed-lifetime-span-mixup-125143.rs create mode 100644 tests/ui/inference/unnamed-lifetime-span-mixup-125143.stderr diff --git a/tests/ui/inference/unnamed-lifetime-span-mixup-125143.rs b/tests/ui/inference/unnamed-lifetime-span-mixup-125143.rs new file mode 100644 index 0000000000000..c9572471607d7 --- /dev/null +++ b/tests/ui/inference/unnamed-lifetime-span-mixup-125143.rs @@ -0,0 +1,42 @@ +struct X; + +// Test that the error correctly differentiate between the two unnamed lifetimes +impl std::ops::Add<&X> for &X { + type Output = X; + + fn add(self, _rhs: Self) -> Self::Output { + X + } +} +//~^^^^ ERROR method not compatible with trait + +// Test that the error correctly differentiate between named and the unnamed lifetimes +impl<'a> std::ops::Mul<&'a X> for &X { + type Output = X; + + fn mul(self, _rhs: Self) -> Self::Output { + X + } +} +//~^^^^ ERROR method not compatible with trait + +// Test that the error correctly differentiate between named and the unnamed lifetimes +impl<'a> std::ops::Sub<&X> for &'a X { + type Output = X; + + fn sub(self, _rhs: Self) -> Self::Output { + X + } +} +//~^^^^ ERROR method not compatible with trait + +// This should pass since the lifetime subtyping will pass typecheck +impl<'a, 'b> std::ops::Div<&'a X> for &'b X where 'a : 'b { + type Output = X; + + fn div(self, _rhs: Self) -> Self::Output { + X + } +} + +fn main() {} diff --git a/tests/ui/inference/unnamed-lifetime-span-mixup-125143.stderr b/tests/ui/inference/unnamed-lifetime-span-mixup-125143.stderr new file mode 100644 index 0000000000000..a81c14b47c14f --- /dev/null +++ b/tests/ui/inference/unnamed-lifetime-span-mixup-125143.stderr @@ -0,0 +1,60 @@ +error[E0308]: method not compatible with trait + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:7:5 + | +LL | fn add(self, _rhs: Self) -> Self::Output { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&X, &X) -> X` + found signature `fn(&X, &X) -> X` +note: the anonymous lifetime as defined here... + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:4:20 + | +LL | impl std::ops::Add<&X> for &X { + | ^ +note: ...does not necessarily outlive the anonymous lifetime as defined here + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:4:28 + | +LL | impl std::ops::Add<&X> for &X { + | ^ + +error[E0308]: method not compatible with trait + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:17:5 + | +LL | fn mul(self, _rhs: Self) -> Self::Output { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&X, &'a X) -> X` + found signature `fn(&X, &X) -> X` +note: the lifetime `'a` as defined here... + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:14:6 + | +LL | impl<'a> std::ops::Mul<&'a X> for &X { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime as defined here + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:14:35 + | +LL | impl<'a> std::ops::Mul<&'a X> for &X { + | ^ + +error[E0308]: method not compatible with trait + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:27:5 + | +LL | fn sub(self, _rhs: Self) -> Self::Output { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&'a X, &X) -> X` + found signature `fn(&'a X, &'a X) -> X` +note: the anonymous lifetime as defined here... + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:24:24 + | +LL | impl<'a> std::ops::Sub<&X> for &'a X { + | ^ +note: ...does not necessarily outlive the lifetime `'a` as defined here + --> $DIR/unnamed-lifetime-span-mixup-125143.rs:24:6 + | +LL | impl<'a> std::ops::Sub<&X> for &'a X { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 2f10c078580af36c3f657ffbb647536078b8e07a Mon Sep 17 00:00:00 2001 From: Mathias Blikstad Date: Thu, 23 May 2024 23:27:06 +0100 Subject: [PATCH 3/3] Lookup anonymous lifetimes with LocalDefId instead of DefId --- compiler/rustc_hir/src/hir.rs | 4 ++-- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 263e84441f46e..cf3017842952b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -571,8 +571,8 @@ impl<'hir> Generics<'hir> { self.params.iter().find(|¶m| name == param.name.ident().name) } - pub fn get_with_def_id(&self, id: DefId) -> Option<&GenericParam<'hir>> { - self.params.iter().find(|¶m| id.index == param.def_id.local_def_index) + pub fn get_with_local_def_id(&self, id: LocalDefId) -> Option<&GenericParam<'hir>> { + self.params.iter().find(|¶m| id == param.def_id) } /// If there are generic parameters, return where to introduce a new one. diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d3babf7ed1894..ee96363fe8df8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -201,11 +201,10 @@ fn msg_span_from_named_region<'tcx>( match *region { ty::ReEarlyParam(ref br) => { let scope = region.free_region_binding_scope(tcx).expect_local(); - let span = if let Some(param) = tcx - .hir() - .get_generics(scope) - .and_then(|generics| generics.get_with_def_id(br.def_id)) - { + let span = if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| { + let local_def_id = br.def_id.expect_local(); + generics.get_with_local_def_id(local_def_id) + }) { param.span } else { tcx.def_span(scope)