Fix bad inherent overlap error

When we examine HIR::ImplBlock's we determine if an impl might overlap
another impl based on the Self type. So for example you might have a
generic structure Foo<T>(T), and an associated impl block for Foo<i32>, but
then go on to define an associated impl of Foo<T> the generic one will
overlap any associated impl hiding the generic implementation.

In this case we have two generic impl blocks

  *const [T]
  *const T

This means the *const T might overlap with the slice one since it is
generic. As bjorn3 pointed out in #1075, the correct implementation is to
observe that [T] is constrained by size but untill we have the auto trait
of Sized we must example the two generic impls and just determine that
they are not-equal so for now this is the best implementation we can do.

Fixes #1075
This commit is contained in:
Philip Herron 2022-03-30 18:13:48 +01:00
parent e43a5c5373
commit 4413bc0cf8
7 changed files with 74 additions and 33 deletions

View File

@ -123,7 +123,26 @@ public:
continue;
if (query->can_eq (candidate, false))
possible_collision (it->second, iy->second);
{
// we might be in the case that we have:
//
// *const T vs *const [T]
//
// so lets use an equality check when the
// candidates are both generic to be sure we dont emit a false
// positive
bool a = query->is_concrete ();
bool b = candidate->is_concrete ();
bool both_generic = !a && !b;
if (both_generic)
{
if (!query->is_equal (*candidate))
continue;
}
possible_collision (it->second, iy->second);
}
}
}
}
@ -152,8 +171,8 @@ public:
void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
const std::string &name)
{
RichLocation r (query->get_locus ());
r.add_range (dup->get_locus ());
RichLocation r (dup->get_locus ());
r.add_range (query->get_locus ());
rust_error_at (r, "duplicate definitions with name %s", name.c_str ());
}

View File

@ -284,7 +284,10 @@ protected:
return;
if (!receiver->can_eq (impl_block_ty, false))
return;
{
if (!impl_block_ty->can_eq (receiver, false))
return;
}
// lets visit the impl_item
item->accept_vis (*this);

View File

@ -41,7 +41,10 @@ TypeBoundsProbe::scan ()
return true;
if (!receiver->can_eq (impl_type, false))
return true;
{
if (!impl_type->can_eq (receiver, false))
return true;
}
possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
return true;

View File

@ -886,8 +886,6 @@ public:
ok = true;
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const ArrayType *base;
@ -916,8 +914,6 @@ public:
ok = true;
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const SliceType *base;
@ -939,8 +935,6 @@ public:
ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL;
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const BoolType *base;
@ -965,8 +959,6 @@ public:
ok = type.get_int_kind () == base->get_int_kind ();
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const IntType *base;
@ -991,8 +983,6 @@ public:
ok = type.get_uint_kind () == base->get_uint_kind ();
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const UintType *base;
@ -1017,8 +1007,6 @@ public:
ok = type.get_float_kind () == base->get_float_kind ();
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const FloatType *base;
@ -1120,8 +1108,6 @@ public:
ok = true;
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const TupleType *base;
@ -1143,8 +1129,6 @@ public:
void visit (const USizeType &type) override { ok = true; }
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const USizeType *base;
@ -1166,8 +1150,6 @@ public:
void visit (const ISizeType &type) override { ok = true; }
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const ISizeType *base;
@ -1189,8 +1171,6 @@ public:
void visit (const CharType &type) override { ok = true; }
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const CharType *base;
@ -1365,8 +1345,6 @@ public:
void visit (const StrType &type) override { ok = true; }
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const StrType *base;
@ -1383,8 +1361,6 @@ public:
void visit (const NeverType &type) override { ok = true; }
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }
const NeverType *base;
@ -1478,8 +1454,6 @@ public:
ok = base->bounds_compatible (type, ref_locus, false);
}
void visit (const ParamType &type) override { ok = true; }
private:
const BaseType *get_base () const override { return base; }

View File

@ -15,7 +15,7 @@ impl Foo<char> {
}
impl<T> Foo<T> {
fn bar(self) -> T { // { dg-error "duplicate definitions with name bar" }
fn bar(self) -> T {
self.a
}
}

View File

@ -1,7 +1,7 @@
struct Foo<A, B>(A, B);
impl<T> Foo<i32, T> {
fn test(a: T) -> T { // { dg-error "duplicate definitions with name test" }
fn test(a: T) -> T {
a
}
}

View File

@ -0,0 +1,42 @@
// { dg-additional-options "-w" }
extern "rust-intrinsic" {
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
}
struct FatPtr<T> {
data: *const T,
len: usize,
}
union Repr<T> {
rust: *const [T],
rust_mut: *mut [T],
raw: FatPtr<T>,
}
impl<T> *const [T] {
pub const fn len(self) -> usize {
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
// Only `std` can make this guarantee.
let a = unsafe { Repr { rust: self }.raw };
a.len
}
pub const fn as_ptr(self) -> *const T {
self as *const T
}
}
impl<T> *const T {
pub const unsafe fn offset(self, count: isize) -> *const T {
unsafe { offset(self, count) }
}
pub const unsafe fn add(self, count: usize) -> Self {
unsafe { self.offset(count as isize) }
}
pub const fn as_ptr(self) -> *const T {
self as *const T
}
}