// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// .
#ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
#define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
#include "rust-hir-type-check-base.h"
#include "rust-type-util.h"
namespace Rust {
namespace Resolver {
class OverlappingImplItemPass : public TypeCheckBase
{
public:
static void go ()
{
OverlappingImplItemPass pass;
// generate mappings
pass.mappings.iterate_impl_items (
[&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
// ignoring trait-impls might need thought later on
if (impl->has_trait_ref ())
return true;
pass.process_impl_item (id, impl_item, impl);
return true;
});
pass.scan ();
}
void process_impl_item (HirId id, HIR::ImplItem *impl_item,
HIR::ImplBlock *impl)
{
// lets make a mapping of impl-item Self type to (impl-item,name):
// {
// impl-type -> [ (item, name), ... ]
// }
HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
TyTy::BaseType *impl_type = nullptr;
bool ok = query_type (impl_type_id, &impl_type);
if (!ok)
return;
std::string impl_item_name = impl_item->get_impl_item_name ();
std::pair elem (impl_item, impl_item_name);
impl_mappings[impl_type].insert (std::move (elem));
}
void scan ()
{
// we can now brute force the map looking for can_eq on each of the
// impl_items_types to look for possible colliding impl blocks;
for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
{
TyTy::BaseType *query = it->first;
for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
{
TyTy::BaseType *candidate = iy->first;
if (query == candidate)
continue;
if (query->can_eq (candidate, false))
{
// 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);
}
}
}
}
void possible_collision (
std::set > query,
std::set > candidate)
{
for (auto &q : query)
{
HIR::ImplItem *query_impl_item = q.first;
std::string query_impl_item_name = q.second;
for (auto &c : candidate)
{
HIR::ImplItem *candidate_impl_item = c.first;
std::string candidate_impl_item_name = c.second;
if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
collision_detected (query_impl_item, candidate_impl_item,
candidate_impl_item_name);
}
}
}
void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
const std::string &name)
{
rich_location r (line_table, dup->get_locus ());
std::string msg = "duplicate definitions for " + name;
r.add_fixit_replace (query->get_locus (), msg.c_str ());
r.add_range (query->get_locus ());
rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
name.c_str ());
}
private:
OverlappingImplItemPass () : TypeCheckBase () {}
std::map > >
impl_mappings;
};
} // namespace Resolver
} // namespace Rust
#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H