(root)/
gcc-13.2.0/
gcc/
rust/
typecheck/
rust-hir-inherent-impl-overlap.h
       1  // Copyright (C) 2020-2023 Free Software Foundation, Inc.
       2  
       3  // This file is part of GCC.
       4  
       5  // GCC is free software; you can redistribute it and/or modify it under
       6  // the terms of the GNU General Public License as published by the Free
       7  // Software Foundation; either version 3, or (at your option) any later
       8  // version.
       9  
      10  // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11  // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13  // for more details.
      14  
      15  // You should have received a copy of the GNU General Public License
      16  // along with GCC; see the file COPYING3.  If not see
      17  // <http://www.gnu.org/licenses/>.
      18  
      19  #ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
      20  #define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
      21  
      22  #include "rust-hir-type-check-base.h"
      23  #include "rust-hir-full.h"
      24  
      25  namespace Rust {
      26  namespace Resolver {
      27  
      28  class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor
      29  {
      30  public:
      31    static bool resolve (HIR::ImplItem *item, std::string &name_result)
      32    {
      33      ImplItemToName resolver (name_result);
      34      item->accept_vis (resolver);
      35      return resolver.ok;
      36    }
      37  
      38    void visit (HIR::TypeAlias &alias) override
      39    {
      40      ok = true;
      41      result.assign (alias.get_new_type_name ());
      42    }
      43  
      44    void visit (HIR::Function &function) override
      45    {
      46      ok = true;
      47      result.assign (function.get_function_name ());
      48    }
      49  
      50    void visit (HIR::ConstantItem &constant) override
      51    {
      52      ok = true;
      53      result.assign (constant.get_identifier ());
      54    }
      55  
      56  private:
      57    ImplItemToName (std::string &result)
      58      : TypeCheckBase (), ok (false), result (result)
      59    {}
      60  
      61    bool ok;
      62    std::string &result;
      63  };
      64  
      65  class OverlappingImplItemPass : public TypeCheckBase
      66  {
      67  public:
      68    static void go ()
      69    {
      70      OverlappingImplItemPass pass;
      71  
      72      // generate mappings
      73      pass.mappings->iterate_impl_items (
      74        [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
      75  	// ignoring trait-impls might need thought later on
      76  	if (impl->has_trait_ref ())
      77  	  return true;
      78  
      79  	pass.process_impl_item (id, impl_item, impl);
      80  	return true;
      81        });
      82  
      83      pass.scan ();
      84    }
      85  
      86    void process_impl_item (HirId id, HIR::ImplItem *impl_item,
      87  			  HIR::ImplBlock *impl)
      88    {
      89      // lets make a mapping of impl-item Self type to (impl-item,name):
      90      // {
      91      //   impl-type -> [ (item, name), ... ]
      92      // }
      93  
      94      HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
      95      TyTy::BaseType *impl_type = nullptr;
      96      bool ok = query_type (impl_type_id, &impl_type);
      97      if (!ok)
      98        return;
      99  
     100      std::string impl_item_name;
     101      ok = ImplItemToName::resolve (impl_item, impl_item_name);
     102      rust_assert (ok);
     103  
     104      std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
     105      impl_mappings[impl_type].insert (std::move (elem));
     106    }
     107  
     108    void scan ()
     109    {
     110      // we can now brute force the map looking for can_eq on each of the
     111      // impl_items_types to look for possible colliding impl blocks;
     112      for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
     113        {
     114  	TyTy::BaseType *query = it->first;
     115  
     116  	for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
     117  	  {
     118  	    TyTy::BaseType *candidate = iy->first;
     119  	    if (query == candidate)
     120  	      continue;
     121  
     122  	    if (query->can_eq (candidate, false))
     123  	      {
     124  		// we might be in the case that we have:
     125  		//
     126  		// *const T vs *const [T]
     127  		//
     128  		// so lets use an equality check when the
     129  		// candidates are both generic to be sure we dont emit a false
     130  		// positive
     131  
     132  		bool a = query->is_concrete ();
     133  		bool b = candidate->is_concrete ();
     134  		bool both_generic = !a && !b;
     135  		if (both_generic)
     136  		  {
     137  		    if (!query->is_equal (*candidate))
     138  		      continue;
     139  		  }
     140  
     141  		possible_collision (it->second, iy->second);
     142  	      }
     143  	  }
     144        }
     145    }
     146  
     147    void possible_collision (
     148      std::set<std::pair<HIR::ImplItem *, std::string> > query,
     149      std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
     150    {
     151      for (auto &q : query)
     152        {
     153  	HIR::ImplItem *query_impl_item = q.first;
     154  	std::string query_impl_item_name = q.second;
     155  
     156  	for (auto &c : candidate)
     157  	  {
     158  	    HIR::ImplItem *candidate_impl_item = c.first;
     159  	    std::string candidate_impl_item_name = c.second;
     160  
     161  	    if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
     162  	      collision_detected (query_impl_item, candidate_impl_item,
     163  				  candidate_impl_item_name);
     164  	  }
     165        }
     166    }
     167  
     168    void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
     169  			   const std::string &name)
     170    {
     171      RichLocation r (dup->get_locus ());
     172      r.add_range (query->get_locus ());
     173      rust_error_at (r, "duplicate definitions with name %s", name.c_str ());
     174    }
     175  
     176  private:
     177    OverlappingImplItemPass () : TypeCheckBase () {}
     178  
     179    std::map<TyTy::BaseType *,
     180  	   std::set<std::pair<HIR::ImplItem *, std::string> > >
     181      impl_mappings;
     182  };
     183  
     184  } // namespace Resolver
     185  } // namespace Rust
     186  
     187  #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H