Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@ impl<'hir> Generics<'hir> {
self.params.iter().find(|&param| name == param.name.ident().name)
}

pub fn get_with_def_id(&self, id: DefId) -> Option<&GenericParam<'hir>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely not correct if DefId comes from a different crate. Please make this take a LocalDefId, or ideally, do the comparison with HirId instead.

Copy link
Contributor Author

@bovinebuddha bovinebuddha May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not able to find a way to convert a DefId to a HirId, so I used a LocalDefId instead. The place where I use it already has expect_local() on the binding scope, so presumably the lifetime should also be local. However, I tried to use the same logic for late bound regions, and that caused a panic in a test for trying to unpack a non-local DefId. Is there a way to get the HirId?

self.params.iter().find(|&param| 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<Span> {
if let Some(first) = self.params.first()
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
42 changes: 42 additions & 0 deletions tests/ui/inference/unnamed-lifetime-span-mixup-125143.rs
Original file line number Diff line number Diff line change
@@ -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() {}
60 changes: 60 additions & 0 deletions tests/ui/inference/unnamed-lifetime-span-mixup-125143.stderr
Original file line number Diff line number Diff line change
@@ -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`.