From c3499198a97d2421990599c884a75ccfc775e122 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 14:46:37 +0100 Subject: Seperate look for undetermined types post type resolution When we do full PathInExpression resolution we can end up with orphaned Inference Variables which never get unified with real concrete types. This is to be expected. What we really care about are that all name declarations are fully typed before we move into the next pass. --- gcc/rust/typecheck/rust-hir-type-check.cc | 54 +++++++++++++++++++++++++------ gcc/rust/typecheck/rust-tyty.h | 19 +++++++++++ 2 files changed, 63 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 8b2f657..681fb24 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -44,9 +44,11 @@ TypeResolution::Resolve (HIR::Crate &crate) if (saw_errors ()) return; + auto resolver = Resolver::Resolver::get (); auto mappings = Analysis::Mappings::get (); auto context = TypeCheckContext::get (); + // default inference variables if possible context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool { if (ty->get_kind () == TyTy::TypeKind::ERROR) { @@ -61,19 +63,51 @@ TypeResolution::Resolve (HIR::Crate &crate) TyTy::InferType *infer_var = (TyTy::InferType *) ty; TyTy::BaseType *default_type; bool ok = infer_var->default_type (&default_type); - if (!ok) + if (ok) { - rust_error_at (mappings->lookup_location (id), - "unable to determine type: please give this a type: %u", - id); - return true; + auto result = ty->unify (default_type); + result->set_ref (id); + context->insert_type ( + Analysis::NodeMapping (mappings->get_current_crate (), 0, id, + UNKNOWN_LOCAL_DEFID), + result); } - auto result = ty->unify (default_type); - result->set_ref (id); - context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), - 0, id, UNKNOWN_LOCAL_DEFID), - result); + return true; + }); + + // scan the ribs to ensure the decls are all setup correctly + resolver->iterate_name_ribs ([&] (Rib *r) -> bool { + r->iterate_decls ([&] (NodeId decl_node_id, Location locus) -> bool { + Definition def; + if (!resolver->lookup_definition (decl_node_id, &def)) + { + rust_error_at (locus, "failed to lookup decl def"); + return true; + } + + HirId hir_node = UNKNOWN_HIRID; + if (!mappings->lookup_node_to_hir (mappings->get_current_crate (), + def.parent, &hir_node)) + { + rust_error_at (locus, "failed to lookup type hir node id"); + return true; + } + // lookup the ty + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (hir_node, &ty); + if (!ok) + { + rust_error_at (locus, "failed to lookup type for decl node_id: %u", + decl_node_id); + return true; + } + + if (!ty->is_concrete ()) + rust_error_at (locus, "unable to determine type"); + + return true; + }); return true; }); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 7b4197f..9cf75fa 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -91,6 +91,8 @@ public: virtual bool is_unit () const { return false; } + virtual bool is_concrete () const { return true; } + TypeKind get_kind () const { return kind; } /* Returns a pointer to a clone of this. The caller is responsible for @@ -194,6 +196,8 @@ public: bool default_type (BaseType **type) const; + bool is_concrete () const final override { return false; } + private: InferTypeKind infer_kind; }; @@ -321,6 +325,16 @@ public: BaseType *clone () final override; + bool is_concrete () const override final + { + for (size_t i = 0; i < num_fields (); i++) + { + if (!get_field (i)->is_concrete ()) + return false; + } + return true; + } + void iterate_fields (std::function cb) const { for (size_t i = 0; i < num_fields (); i++) @@ -824,6 +838,11 @@ public: BaseType *clone () final override; + bool is_concrete () const final override + { + return get_element_type ()->is_concrete (); + } + private: size_t capacity; TyVar element_type; -- cgit v1.1 From 0c5a6af749de89d5e21a525e74b94b01b3f3b35f Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:16:50 +0100 Subject: Unify ADTRules needs to check identifier When unifying algebraic data types we must check the identifiers match as well as everything else. We also should not be relying on nullptr checks for resolution failures but use TyTy::Error nodes. --- gcc/rust/typecheck/rust-tyty-rules.h | 40 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index 0fb04c5..c23cbc1 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -67,8 +67,8 @@ public: } other->accept_vis (*this); - if (resolved == nullptr) - return nullptr; + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + return resolved; resolved->append_reference (get_base ()->get_ref ()); resolved->append_reference (other->get_ref ()); @@ -81,7 +81,7 @@ public: bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER; bool results_is_non_general_infer_var = (result_is_infer_var - && ((InferType *) resolved)->get_infer_kind () + && (static_cast (resolved))->get_infer_kind () != TyTy::InferType::GENERAL); if (result_resolved || results_is_non_general_infer_var) { @@ -229,7 +229,7 @@ public: virtual void visit (ParamType &type) override { Location ref_locus = mappings->lookup_location (type.get_ref ()); - rust_error_at (ref_locus, "expected [%s] got [ParamTy <%s>]", + rust_error_at (ref_locus, "expected [%s] got [%s]", get_base ()->as_string ().c_str (), type.as_string ().c_str ()); } @@ -829,6 +829,12 @@ public: void visit (ADTType &type) override { + if (base->get_identifier ().compare (type.get_identifier ()) != 0) + { + BaseRules::visit (type); + return; + } + if (base->num_fields () != type.num_fields ()) { BaseRules::visit (type); @@ -844,11 +850,8 @@ public: TyTy::BaseType *other_field_ty = other_field->get_field_type (); BaseType *unified_ty = this_field_ty->unify (other_field_ty); - if (unified_ty == nullptr) - { - BaseRules::visit (type); - return; - } + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + return; } resolved = type.clone (); @@ -882,11 +885,8 @@ public: BaseType *fo = type.get_field (i); BaseType *unified_ty = bo->unify (fo); - if (unified_ty == nullptr) - { - BaseRules::visit (type); - return; - } + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + return; fields.push_back (TyVar (unified_ty->get_ref ())); } @@ -1034,6 +1034,7 @@ public: { if (base->get_ref () == base->get_ty_ref ()) return BaseRules::unify (other); + auto context = Resolver::TypeCheckContext::get (); BaseType *lookup = nullptr; bool ok = context->lookup_type (base->get_ty_ref (), &lookup); @@ -1053,6 +1054,17 @@ public: resolved = type.clone (); } + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + } + private: BaseType *get_base () override { return base; } -- cgit v1.1 From 3fa740f4ff0475809edd45de9fb03b12e1f2a389 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:17:19 +0100 Subject: Add TyTy::BaseType::can_eq method to tyty module When we are probing paths we dont want to unify types as we are testing to find something so a can_eq method simialr to unify but does not throw errors allows for testing if types could be compatible. --- gcc/rust/typecheck/rust-tyty-cmp.h | 812 +++++++++++++++++++++ gcc/rust/typecheck/rust-tyty.cc | 124 +++- gcc/rust/typecheck/rust-tyty.h | 79 +- gcc/testsuite/rust.test/xfail_compile/tuple1.rs | 1 + .../rust.test/xfail_compile/type-alias1.rs | 1 + 5 files changed, 1006 insertions(+), 11 deletions(-) create mode 100644 gcc/rust/typecheck/rust-tyty-cmp.h (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h new file mode 100644 index 0000000..e2e0d08 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -0,0 +1,812 @@ +// Copyright (C) 2020 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_TYTY_CMP_H +#define RUST_TYTY_CMP_H + +#include "rust-diagnostics.h" +#include "rust-tyty.h" +#include "rust-tyty-visitor.h" +#include "rust-hir-map.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace TyTy { + +class BaseCmp : public TyVisitor +{ +public: + virtual bool can_eq (BaseType *other) + { + if (other->get_kind () == TypeKind::PARAM) + { + ParamType *p = static_cast (other); + if (p->can_resolve ()) + { + other = p->resolve (); + } + } + + other->accept_vis (*this); + return ok; + } + + virtual void visit (TupleType &) override { ok = false; } + + virtual void visit (ADTType &) override { ok = false; } + + virtual void visit (InferType &) override { ok = false; } + + virtual void visit (FnType &) override { ok = false; } + + virtual void visit (FnPtr &) override { ok = false; } + + virtual void visit (ArrayType &) override { ok = false; } + + virtual void visit (BoolType &) override { ok = false; } + + virtual void visit (IntType &) override { ok = false; } + + virtual void visit (UintType &) override { ok = false; } + + virtual void visit (USizeType &) override { ok = false; } + + virtual void visit (ISizeType &) override { ok = false; } + + virtual void visit (FloatType &) override { ok = false; } + + virtual void visit (ErrorType &) override { ok = false; } + + virtual void visit (CharType &) override { ok = false; } + + virtual void visit (ReferenceType &) override { ok = false; } + + virtual void visit (ParamType &) override + { + // it is ok for types to can eq to a ParamType + ok = true; + } + + virtual void visit (StrType &) override { ok = false; } + +protected: + BaseCmp (BaseType *base) + : mappings (Analysis::Mappings::get ()), + context (Resolver::TypeCheckContext::get ()), ok (false) + {} + + Analysis::Mappings *mappings; + Resolver::TypeCheckContext *context; + + bool ok; + +private: + /* Returns a pointer to the ty that created this rule. */ + virtual BaseType *get_base () = 0; +}; + +class InferCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + InferCmp (InferType *base) : BaseCmp (base), base (base) {} + + void visit (BoolType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (IntType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (UintType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (USizeType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ISizeType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (FloatType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ArrayType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ADTType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (TupleType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (InferType &type) override + { + switch (base->get_infer_kind ()) + { + case InferType::InferTypeKind::GENERAL: + ok = true; + return; + + case InferType::InferTypeKind::INTEGRAL: { + if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) + { + ok = true; + return; + } + else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) + { + ok = true; + return; + } + } + break; + + case InferType::InferTypeKind::FLOAT: { + if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) + { + ok = true; + return; + } + else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) + { + ok = true; + return; + } + } + break; + } + + BaseCmp::visit (type); + } + + void visit (CharType &type) override + { + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + } + + void visit (ReferenceType &type) override + + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ParamType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + +private: + BaseType *get_base () override { return base; } + + InferType *base; +}; + +class FnCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FnCmp (FnType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + + void visit (FnType &type) override + { + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto a = base->param_at (i).second; + auto b = type.param_at (i).second; + + auto unified_param = a->unify (b); + if (unified_param == nullptr) + { + BaseCmp::visit (type); + return; + } + } + + auto unified_return + = base->get_return_type ()->unify (type.get_return_type ()); + if (unified_return == nullptr) + { + BaseCmp::visit (type); + return; + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + FnType *base; +}; + +class FnptrCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FnptrCmp (FnPtr *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseCmp::visit (type); + return; + } + + ok = true; + } + + void visit (FnPtr &type) override + { + auto this_ret_type = base->get_return_type (); + auto other_ret_type = type.get_return_type (); + auto unified_result = this_ret_type->unify (other_ret_type); + if (unified_result == nullptr + || unified_result->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto this_param = base->param_at (i); + auto other_param = type.param_at (i); + auto unified_param = this_param->unify (other_param); + if (unified_param == nullptr + || unified_param->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + + void visit (FnType &type) override + { + auto this_ret_type = base->get_return_type (); + auto other_ret_type = type.get_return_type (); + auto unified_result = this_ret_type->unify (other_ret_type); + if (unified_result == nullptr + || unified_result->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto this_param = base->param_at (i); + auto other_param = type.param_at (i).second; + auto unified_param = this_param->unify (other_param); + if (unified_param == nullptr + || unified_param->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + FnPtr *base; +}; + +class ArrayCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ArrayCmp (ArrayType *base) : BaseCmp (base), base (base) {} + + void visit (ArrayType &type) override + { + // check base type + auto base_resolved + = base->get_element_type ()->unify (type.get_element_type ()); + if (base_resolved == nullptr) + { + BaseCmp::visit (type); + return; + } + + // need to check the base types and capacity + if (type.get_capacity () != base->get_capacity ()) + { + Location locus = mappings->lookup_location (type.get_ref ()); + rust_error_at (locus, "mismatch in array capacity"); + BaseCmp::visit (type); + return; + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + ArrayType *base; +}; + +class BoolCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + BoolCmp (BoolType *base) : BaseCmp (base), base (base) {} + + void visit (BoolType &type) override { ok = true; } + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + +private: + BaseType *get_base () override { return base; } + + BoolType *base; +}; + +class IntCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + IntCmp (IntType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (IntType &type) override + { + ok = type.get_int_kind () == base->get_int_kind (); + } + +private: + BaseType *get_base () override { return base; } + + IntType *base; +}; + +class UintCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + UintCmp (UintType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (UintType &type) override + { + ok = type.get_uint_kind () == base->get_uint_kind (); + } + +private: + BaseType *get_base () override { return base; } + + UintType *base; +}; + +class FloatCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FloatCmp (FloatType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::INTEGRAL; + } + + void visit (FloatType &type) override + { + ok = type.get_float_kind () == base->get_float_kind (); + } + +private: + BaseType *get_base () override { return base; } + + FloatType *base; +}; + +class ADTCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ADTCmp (ADTType *base) : BaseCmp (base), base (base) {} + + void visit (ADTType &type) override + { + if (base->get_identifier ().compare (type.get_identifier ()) != 0) + { + BaseCmp::visit (type); + return; + } + + if (base->num_fields () != type.num_fields ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < type.num_fields (); ++i) + { + TyTy::StructFieldType *base_field = base->get_field (i); + TyTy::StructFieldType *other_field = type.get_field (i); + + TyTy::BaseType *this_field_ty = base_field->get_field_type (); + TyTy::BaseType *other_field_ty = other_field->get_field_type (); + + if (!this_field_ty->can_eq (other_field_ty)) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + ADTType *base; +}; + +class TupleCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + TupleCmp (TupleType *base) : BaseCmp (base), base (base) {} + + void visit (TupleType &type) override + { + if (base->num_fields () != type.num_fields ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_fields (); i++) + { + BaseType *bo = base->get_field (i); + BaseType *fo = type.get_field (i); + + if (!bo->can_eq (fo)) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + TupleType *base; +}; + +class USizeCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + USizeCmp (USizeType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (USizeType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + USizeType *base; +}; + +class ISizeCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ISizeCmp (ISizeType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (ISizeType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + ISizeType *base; +}; + +class CharCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + CharCmp (CharType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + + void visit (CharType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + CharType *base; +}; + +class ReferenceCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ReferenceCmp (ReferenceType *base) : BaseCmp (base), base (base) {} + + void visit (ReferenceType &type) override + { + auto base_type = base->get_base (); + auto other_base_type = type.get_base (); + + ok = base_type->can_eq (other_base_type); + } + +private: + BaseType *get_base () override { return base; } + + ReferenceType *base; +}; + +class ParamCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ParamCmp (ParamType *base) : BaseCmp (base), base (base) {} + + // param types are a placeholder we shouldn't have cases where we unify + // against it. eg: struct foo { a: T }; When we invoke it we can do either: + // + // foo{ a: 123 }. + // Then this enforces the i32 type to be referenced on the + // field via an hirid. + // + // rust also allows for a = foo{a:123}; Where we can use an Inference Variable + // to handle the typing of the struct + bool can_eq (BaseType *other) override final + { + if (base->get_ref () == base->get_ty_ref ()) + return BaseCmp::can_eq (other); + + auto context = Resolver::TypeCheckContext::get (); + BaseType *lookup = nullptr; + bool ok = context->lookup_type (base->get_ty_ref (), &lookup); + rust_assert (ok); + + return lookup->can_eq (other); + } + + void visit (ParamType &type) override + { + ok = base->get_symbol ().compare (type.get_symbol ()) == 0; + } + +private: + BaseType *get_base () override { return base; } + + ParamType *base; +}; + +class StrCmp : public BaseCmp +{ + // FIXME we will need a enum for the StrType like ByteBuf etc.. + using Rust::TyTy::BaseCmp::visit; + +public: + StrCmp (StrType *base) : BaseCmp (base), base (base) {} + + void visit (StrType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + StrType *base; +}; + +} // namespace TyTy +} // namespace Rust + +#endif // RUST_TYTY_CMP_H diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index cb0543c..8f2faec 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-tyty-rules.h" +#include "rust-tyty-cmp.h" #include "rust-hir-map.h" #include "rust-substitution-mapper.h" @@ -91,6 +92,13 @@ InferType::unify (BaseType *other) return r.unify (other); } +bool +InferType::can_eq (BaseType *other) +{ + InferCmp r (this); + return r.can_eq (other); +} + BaseType * InferType::clone () { @@ -107,11 +115,13 @@ InferType::default_type (BaseType **type) const { case GENERAL: return false; + case INTEGRAL: { ok = context->lookup_builtin ("i32", type); rust_assert (ok); return ok; } + case FLOAT: { ok = context->lookup_builtin ("f64", type); rust_assert (ok); @@ -139,6 +149,12 @@ ErrorType::unify (BaseType *other) return this; } +bool +ErrorType::can_eq (BaseType *other) +{ + return get_kind () == other->get_kind (); +} + BaseType * ErrorType::clone () { @@ -304,6 +320,13 @@ ADTType::unify (BaseType *other) } bool +ADTType::can_eq (BaseType *other) +{ + ADTCmp r (this); + return r.can_eq (other); +} + +bool ADTType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -418,8 +441,7 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) BaseType *concrete = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings); - if (concrete == nullptr - || concrete->get_kind () == TyTy::TypeKind::ERROR) + if (concrete->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (subst_mappings.get_locus (), "Failed to resolve field substitution type: %s", @@ -470,6 +492,13 @@ TupleType::unify (BaseType *other) } bool +TupleType::can_eq (BaseType *other) +{ + TupleCmp r (this); + return r.can_eq (other); +} + +bool TupleType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -524,6 +553,13 @@ FnType::unify (BaseType *other) } bool +FnType::can_eq (BaseType *other) +{ + FnCmp r (this); + return r.can_eq (other); +} + +bool FnType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -713,6 +749,13 @@ FnPtr::unify (BaseType *other) } bool +FnPtr::can_eq (BaseType *other) +{ + FnptrCmp r (this); + return r.can_eq (other); +} + +bool FnPtr::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -767,6 +810,13 @@ ArrayType::unify (BaseType *other) } bool +ArrayType::can_eq (BaseType *other) +{ + ArrayCmp r (this); + return r.can_eq (other); +} + +bool ArrayType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -814,6 +864,13 @@ BoolType::unify (BaseType *other) return r.unify (other); } +bool +BoolType::can_eq (BaseType *other) +{ + BoolCmp r (this); + return r.can_eq (other); +} + BaseType * BoolType::clone () { @@ -853,6 +910,13 @@ IntType::unify (BaseType *other) return r.unify (other); } +bool +IntType::can_eq (BaseType *other) +{ + IntCmp r (this); + return r.can_eq (other); +} + BaseType * IntType::clone () { @@ -903,6 +967,13 @@ UintType::unify (BaseType *other) return r.unify (other); } +bool +UintType::can_eq (BaseType *other) +{ + UintCmp r (this); + return r.can_eq (other); +} + BaseType * UintType::clone () { @@ -947,6 +1018,13 @@ FloatType::unify (BaseType *other) return r.unify (other); } +bool +FloatType::can_eq (BaseType *other) +{ + FloatCmp r (this); + return r.can_eq (other); +} + BaseType * FloatType::clone () { @@ -983,6 +1061,13 @@ USizeType::unify (BaseType *other) return r.unify (other); } +bool +USizeType::can_eq (BaseType *other) +{ + USizeCmp r (this); + return r.can_eq (other); +} + BaseType * USizeType::clone () { @@ -1008,6 +1093,13 @@ ISizeType::unify (BaseType *other) return r.unify (other); } +bool +ISizeType::can_eq (BaseType *other) +{ + ISizeCmp r (this); + return r.can_eq (other); +} + BaseType * ISizeType::clone () { @@ -1033,6 +1125,13 @@ CharType::unify (BaseType *other) return r.unify (other); } +bool +CharType::can_eq (BaseType *other) +{ + CharCmp r (this); + return r.can_eq (other); +} + BaseType * CharType::clone () { @@ -1059,6 +1158,13 @@ ReferenceType::unify (BaseType *other) } bool +ReferenceType::can_eq (BaseType *other) +{ + ReferenceCmp r (this); + return r.can_eq (other); +} + +bool ReferenceType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -1110,6 +1216,13 @@ ParamType::unify (BaseType *other) return r.unify (other); } +bool +ParamType::can_eq (BaseType *other) +{ + ParamCmp r (this); + return r.can_eq (other); +} + BaseType * ParamType::clone () { @@ -1179,6 +1292,13 @@ StrType::unify (BaseType *other) } bool +StrType::can_eq (BaseType *other) +{ + StrCmp r (this); + return r.can_eq (other); +} + +bool StrType::is_equal (const BaseType &other) const { return get_kind () == other.get_kind (); diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 9cf75fa..c428c4c 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -75,15 +75,20 @@ public: virtual std::string get_name () const = 0; - /* Unify two types. Returns a pointer to the newly-created unified ty, or - nullptr if the two ty cannot be unified. The caller is responsible for - releasing the memory of the returned ty. */ + // Unify two types. Returns a pointer to the newly-created unified ty, or + // nullptr if the two ty cannot be unified. The caller is responsible for + // releasing the memory of the returned ty. using ignore_errors alows for a + // can_eq style unification virtual BaseType *unify (BaseType *other) = 0; - /* Check value equality between two ty. Type inference rules are ignored. Two - ty are considered equal if they're of the same kind, and - 1. (For ADTs, arrays, tuples, refs) have the same underlying ty - 2. (For functions) have the same signature */ + // similar to unify but does not actually perform type unification but + // determines whether they are compatible + virtual bool can_eq (BaseType *other) = 0; + + // Check value equality between two ty. Type inference rules are ignored. Two + // ty are considered equal if they're of the same kind, and + // 1. (For ADTs, arrays, tuples, refs) have the same underlying ty + // 2. (For functions) have the same signature virtual bool is_equal (const BaseType &other) const { return get_kind () == other.get_kind (); @@ -113,6 +118,8 @@ public: return supports_substitutions () && has_subsititions_defined (); } + virtual bool needs_generic_substitutions () const { return false; } + std::string mappings_str () const { std::string buffer = "Ref: " + std::to_string (get_ref ()) @@ -129,7 +136,11 @@ public: return as_string () + ":" + mappings_str (); } - void debug () const { printf ("%s\n", debug_str ().c_str ()); } + void debug () const + { + printf ("[%p] %s\n", static_cast (this), + debug_str ().c_str ()); + } protected: BaseType (HirId ref, HirId ty_ref, TypeKind kind, @@ -188,6 +199,8 @@ public: BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; + BaseType *clone () final override; InferTypeKind get_infer_kind () const { return infer_kind; } @@ -220,6 +233,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; @@ -246,6 +260,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; @@ -316,6 +331,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -419,6 +435,12 @@ public: static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); } + bool is_conrete () const + { + return argument != nullptr && argument->get_kind () != TyTy::TypeKind::ERROR + && argument->get_kind () != TyTy::TypeKind::PARAM; + } + std::string as_string () const { return param->as_string () + ":" + argument->as_string (); @@ -473,6 +495,19 @@ public: return false; } + // is_concrete means if the used args is non error, ie: non empty this will + // verify if actual real types have been put in place of are they still + // ParamTy + bool is_concrete () const + { + for (auto &mapping : mappings) + { + if (!mapping.is_conrete ()) + return false; + } + return true; + } + Location get_locus () { return locus; } size_t size () const { return mappings.size (); } @@ -543,7 +578,8 @@ public: bool needs_substitution () const { - return has_substitutions () && used_arguments.is_error (); + return has_substitutions () + && (used_arguments.is_error () || !used_arguments.is_concrete ()); } bool was_substituted () const { return !needs_substitution (); } @@ -622,11 +658,14 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; size_t num_fields () const { return fields.size (); } + std::string get_identifier () const { return identifier; } + std::string get_name () const override final { return identifier + subst_as_string (); @@ -671,6 +710,11 @@ public: } } + bool needs_generic_substitutions () const override final + { + return needs_substitution (); + } + bool supports_substitutions () const override final { return true; } bool has_subsititions_defined () const override final @@ -716,6 +760,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -745,6 +790,11 @@ public: BaseType *clone () final override; + bool needs_generic_substitutions () const override final + { + return needs_substitution (); + } + bool supports_substitutions () const override final { return true; } bool has_subsititions_defined () const override final @@ -788,6 +838,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -829,6 +880,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -866,6 +918,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -898,6 +951,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; IntKind get_int_kind () const { return int_kind; } @@ -937,6 +991,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; UintKind get_uint_kind () const { return uint_kind; } @@ -974,6 +1029,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; FloatKind get_float_kind () const { return float_kind; } @@ -1013,6 +1069,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1045,6 +1102,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1077,6 +1135,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1113,6 +1172,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -1150,6 +1210,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; diff --git a/gcc/testsuite/rust.test/xfail_compile/tuple1.rs b/gcc/testsuite/rust.test/xfail_compile/tuple1.rs index 84179b1..67a33f4 100644 --- a/gcc/testsuite/rust.test/xfail_compile/tuple1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/tuple1.rs @@ -1,3 +1,4 @@ +// { dg-excess-errors "Noisy error and debug" } fn main() { let a: (i32, bool) = (123, 123); // { dg-error "expected .bool. got .." } let b; diff --git a/gcc/testsuite/rust.test/xfail_compile/type-alias1.rs b/gcc/testsuite/rust.test/xfail_compile/type-alias1.rs index c7d7048..53b4923 100644 --- a/gcc/testsuite/rust.test/xfail_compile/type-alias1.rs +++ b/gcc/testsuite/rust.test/xfail_compile/type-alias1.rs @@ -1,3 +1,4 @@ +// { dg-excess-errors "Noisy error and debug" } type TypeAlias = (i32, u32); fn main() { -- cgit v1.1 From 826ce3c92d69b2f2ff9d11ad39cd0843fcc21a05 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:26:31 +0100 Subject: Add impl mappings to inherent impl items When lowering impl blocks to HIR we keep track of all the inherent impl items for lookup later but we also need to be able to reverse lookup impl items back to their respective impl block. --- gcc/rust/hir/rust-ast-lower-item.h | 9 +++++++++ gcc/rust/hir/tree/rust-hir-path.h | 6 ++++++ gcc/rust/util/rust-hir-map.cc | 19 +++++++++++++++++++ gcc/rust/util/rust-hir-map.h | 27 ++++++++++++++++----------- 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index edbc498..18ead3c 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -360,12 +360,14 @@ public: mappings->get_next_localdef_id (crate_num)); std::vector > impl_items; + std::vector impl_item_ids; for (auto &impl_item : impl_block.get_impl_items ()) { HIR::InherentImplItem *lowered = ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ()); impl_items.push_back (std::unique_ptr (lowered)); + impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ()); } translated @@ -381,6 +383,13 @@ public: translated); mappings->insert_location (crate_num, mapping.get_hirid (), impl_block.get_locus ()); + + for (auto &impl_item_id : impl_item_ids) + { + mappings->insert_impl_item_mapping (impl_item_id, + static_cast ( + translated)); + } } private: diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 8dbde9c..d6f9fc0 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -255,6 +255,12 @@ public: } } + size_t get_num_segments () const { return segments.size (); } + + std::vector &get_segments () { return segments; } + + PathExprSegment &get_root_seg () { return segments.at (0); } + PathExprSegment get_final_segment () const { return segments.back (); } }; diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 891618e..0dcbd4f 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -524,5 +524,24 @@ Mappings::resolve_nodeid_to_stmt (CrateNum crate, NodeId id, HIR::Stmt **stmt) return resolved_stmt != nullptr; } +void +Mappings::iterate_impl_items ( + std::function cb) +{ + for (auto it = hirImplItemMappings.begin (); it != hirImplItemMappings.end (); + it++) + { + for (auto iy = it->second.begin (); iy != it->second.end (); iy++) + { + auto id = iy->first; + auto impl_item = iy->second.second; + auto impl = lookup_associated_impl ( + impl_item->get_impl_mappings ().get_hirid ()); + if (!cb (id, impl_item, impl)) + return; + } + } +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 2e8a629..9777ee3 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -158,20 +158,24 @@ public: return hirNodesWithinCrate[crate]; } - void - iterate_impl_items (std::function cb) + void insert_impl_item_mapping (HirId impl_item_id, HIR::InherentImpl *impl) { - for (auto it = hirImplItemMappings.begin (); - it != hirImplItemMappings.end (); it++) - { - for (auto iy = it->second.begin (); iy != it->second.end (); iy++) - { - if (!cb (iy->first, iy->second.second)) - return; - } - } + rust_assert (hirImplItemsToImplMappings.find (impl_item_id) + == hirImplItemsToImplMappings.end ()); + hirImplItemsToImplMappings[impl_item_id] = impl; } + HIR::InherentImpl *lookup_associated_impl (HirId impl_item_id) + { + auto lookup = hirImplItemsToImplMappings.find (impl_item_id); + rust_assert (lookup != hirImplItemsToImplMappings.end ()); + return lookup->second; + } + + void iterate_impl_items ( + std::function + cb); + private: Mappings (); @@ -198,6 +202,7 @@ private: std::map > > hirImplItemMappings; std::map > hirSelfParamMappings; + std::map hirImplItemsToImplMappings; // location info std::map > locations; -- cgit v1.1 From f98ccb3a0bcf6a49b4e1f2080f7f58fe39794fdf Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:27:56 +0100 Subject: Refactor backend PathInExpr This method only ever should accept HIR::PathInExpressions. --- gcc/rust/backend/rust-compile-expr.h | 2 +- gcc/rust/backend/rust-compile-resolve-path.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index d0c752c..f98ebc6 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -526,7 +526,7 @@ public: void visit (HIR::PathInExpression &expr) override { - translated = ResolvePathRef::Compile (&expr, ctx); + translated = ResolvePathRef::Compile (expr, ctx); } void visit (HIR::LoopExpr &expr) override diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h index da1d97e..30486d0 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.h +++ b/gcc/rust/backend/rust-compile-resolve-path.h @@ -30,10 +30,10 @@ class ResolvePathRef : public HIRCompileBase using Rust::Compile::HIRCompileBase::visit; public: - static Bexpression *Compile (HIR::Expr *expr, Context *ctx) + static Bexpression *Compile (HIR::PathInExpression &expr, Context *ctx) { ResolvePathRef resolver (ctx); - expr->accept_vis (resolver); + expr.accept_vis (resolver); return resolver.resolved; } -- cgit v1.1 From 5fe4984806be69154e2a48be58965eb67a4be300 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:31:14 +0100 Subject: Add path probe for inherent impl item candidates When performing PathInExpression resolution we need to probe for candidates in impl blocks which can_eq to the Self type. This could be reused to clean up Method resolution and implement PathInExpression resolution properly. --- gcc/rust/typecheck/rust-hir-path-probe.h | 162 +++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 gcc/rust/typecheck/rust-hir-path-probe.h (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h new file mode 100644 index 0000000..a838565 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -0,0 +1,162 @@ +// Copyright (C) 2020 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_PATH_PROBE_H +#define RUST_HIR_PATH_PROBE_H + +#include "rust-hir-type-check-base.h" +#include "rust-hir-full.h" +#include "rust-tyty.h" +#include "rust-substitution-mapper.h" + +namespace Rust { +namespace Resolver { + +struct PathProbeCandidate +{ + HIR::InherentImplItem *impl_item; + TyTy::BaseType *ty; +}; + +class PathProbeType : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static std::vector + Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name) + { + PathProbeType probe (receiver, segment_name); + probe.mappings->iterate_impl_items ( + [&] (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) mutable -> bool { + probe.process_candidate (id, item, impl); + return true; + }); + return probe.candidates; + } + + void process_candidate (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) + { + HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); + TyTy::BaseType *impl_block_ty = nullptr; + bool ok = context->lookup_type (impl_ty_id, &impl_block_ty); + rust_assert (ok); + + if (!receiver->can_eq (impl_block_ty)) + return; + + // lets visit the impl_item + item->accept_vis (*this); + } + + void visit (HIR::ConstantItem &constant) override + { + Identifier name = constant.get_identifier (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = constant.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&constant, ty}; + candidates.push_back (std::move (candidate)); + } + } + + void visit (HIR::Function &function) override + { + Identifier name = function.get_function_name (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = function.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&function, ty}; + candidates.push_back (std::move (candidate)); + } + } + + void visit (HIR::Method &method) override + { + Identifier name = method.get_method_name (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = method.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&method, ty}; + candidates.push_back (std::move (candidate)); + } + } + +private: + PathProbeType (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query) + : TypeCheckBase (), receiver (receiver), search (query) + {} + + TyTy::BaseType *receiver; + const HIR::PathIdentSegment &search; + std::vector candidates; +}; + +class ReportMultipleCandidateError : private TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static void Report (std::vector &candidates, + const HIR::PathIdentSegment &query, Location query_locus) + { + rust_error_at (query_locus, "multiple applicable items in scope for: %s", + query.as_string ().c_str ()); + + ReportMultipleCandidateError visitor; + for (auto &c : candidates) + c.impl_item->accept_vis (visitor); + } + + void visit (HIR::ConstantItem &constant) override + { + rust_error_at (constant.get_locus (), "possible candidate"); + } + + void visit (HIR::Function &function) override + { + rust_error_at (function.get_locus (), "possible candidate"); + } + + void visit (HIR::Method &method) override + { + rust_error_at (method.get_locus (), "possible candidate"); + } + +private: + ReportMultipleCandidateError () : TypeCheckBase () {} +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_PATH_PROBE_H -- cgit v1.1 From 85f587410612c8d2ec65dd23063a849d13005957 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 15:31:29 +0100 Subject: Add Canonical paths to name resolution In order to support name resolution and checks for duplicate definitions of names we need canonical paths for all DefId items such as inherent impl items and normal items. Consider: struct Foo(T); impl Foo { fn name()... } impl Foo { fn name()... } Each of the impl blocks have a name function but these are seperate due to the concrete impl of the Parameter type passed in. The caveat here is that to call this Function name the programmer must be explicit in which implentation they wish to call such as: let a = Foo::::name(); This lets the Path probe lookup the apropriate impl block. The problem here is that rust also allows for the compiler to infer the impl you wish such as: let a = Foo::name(); This should fail since there are multiple candidates possible for this Path. Unless there might have only been one name function in which case it would have worked. This does not support looking for any inherent impl items overlapping such as: rustc_typeck/src/coherence/inherent_impls_overlap.rs - see #353 Fixes #355 #335 #325 --- gcc/rust/resolve/rust-ast-resolve-expr.h | 25 +-- gcc/rust/resolve/rust-ast-resolve-implitem.h | 44 ++--- gcc/rust/resolve/rust-ast-resolve-item.h | 9 +- gcc/rust/resolve/rust-ast-resolve-pattern.h | 18 +- gcc/rust/resolve/rust-ast-resolve-toplevel.h | 54 ++++-- gcc/rust/resolve/rust-ast-resolve-type.h | 159 +++++++++++----- gcc/rust/resolve/rust-ast-resolve.cc | 210 ++++++++++++++++----- gcc/rust/resolve/rust-ast-verify-assignee.h | 3 +- gcc/rust/resolve/rust-name-resolver.h | 88 +++++++-- gcc/rust/typecheck/rust-hir-method-resolve.h | 3 +- gcc/rust/typecheck/rust-hir-type-check-expr.h | 203 ++++++++++++++------ gcc/rust/typecheck/rust-hir-type-check-stmt.h | 2 +- .../typecheck/rust-hir-type-check-struct-field.h | 2 - gcc/rust/typecheck/rust-hir-type-check.cc | 84 +-------- gcc/rust/typecheck/rust-substitution-mapper.h | 5 + gcc/testsuite/rust.test/compile/generics13.rs | 34 ++++ gcc/testsuite/rust.test/compile/generics14.rs | 17 ++ gcc/testsuite/rust.test/xfail_compile/generics6.rs | 29 +++ .../rust.test/xfail_compile/redef_error6.rs | 14 ++ 19 files changed, 686 insertions(+), 317 deletions(-) create mode 100644 gcc/testsuite/rust.test/compile/generics13.rs create mode 100644 gcc/testsuite/rust.test/compile/generics14.rs create mode 100644 gcc/testsuite/rust.test/xfail_compile/generics6.rs create mode 100644 gcc/testsuite/rust.test/xfail_compile/redef_error6.rs (limited to 'gcc') diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 48cc18e..fbf05f2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -109,15 +109,16 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) { resolver->insert_resolved_name (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), Definition{expr.get_node_id (), parent}); } - else if (resolver->get_type_scope ().lookup (expr.as_string (), - &resolved_node)) + else if (resolver->get_type_scope ().lookup ( + CanonicalPath (expr.as_string ()), &resolved_node)) { resolver->insert_resolved_type (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), @@ -255,8 +256,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -281,8 +283,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); @@ -311,8 +313,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -338,8 +341,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h index d88b275f..46343c2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-implitem.h +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -31,25 +31,19 @@ class ResolveToplevelImplItem : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::InherentImplItem *item, AST::Type *base) + static void go (AST::InherentImplItem *item, const CanonicalPath &prefix) { - ResolveToplevelImplItem resolver (base); - if (resolver.base_path.is_empty ()) - { - rust_error_at (base->get_locus_slow (), - "failed to resolve simple path"); - return; - } + ResolveToplevelImplItem resolver (prefix); item->accept_vis (resolver); } void visit (AST::ConstantItem &constant) override { - std::string identifier - = base_path.as_string () + "::" + constant.get_identifier (); + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - identifier, constant.get_node_id (), constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -60,11 +54,11 @@ public: void visit (AST::Function &function) override { - std::string identifier - = base_path.as_string () + "::" + function.get_function_name (); + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - identifier, function.get_node_id (), function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -75,11 +69,11 @@ public: void visit (AST::Method &method) override { - std::string identifier - = base_path.as_string () + "::" + method.get_method_name (); + auto path + = prefix.append (ResolveMethodItemToCanonicalPath::resolve (method)); resolver->get_name_scope ().insert ( - identifier, method.get_node_id (), method.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, method.get_node_id (), method.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (method.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -89,15 +83,13 @@ public: } private: - ResolveToplevelImplItem (AST::Type *base) - : ResolverBase (UNKNOWN_NODEID), base (base), - base_path (AST::SimplePath::create_empty ()) + ResolveToplevelImplItem (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) { - ResolveTypeToSimplePath::go (base, base_path, true); + rust_assert (!prefix.is_error ()); } - AST::Type *base; - AST::SimplePath base_path; + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 45d94db..9c19ce6 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -179,18 +179,21 @@ public: } } + bool canonicalize_type_with_generics = false; NodeId resolved_node = ResolveType::go (impl_block.get_type ().get (), - impl_block.get_node_id ()); + impl_block.get_node_id (), + canonicalize_type_with_generics); if (resolved_node == UNKNOWN_NODEID) return; + auto Self = CanonicalPath::get_big_self (); resolver->get_type_scope ().insert ( - "Self", resolved_node, impl_block.get_type ()->get_locus_slow ()); + Self, resolved_node, impl_block.get_type ()->get_locus_slow ()); for (auto &impl_item : impl_block.get_impl_items ()) impl_item->accept_vis (*this); - resolver->get_type_scope ().peek ()->clear_name ("Self", resolved_node); + resolver->get_type_scope ().peek ()->clear_name (Self, resolved_node); resolver->get_type_scope ().pop (); } diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 147bf72..0734908 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -33,7 +33,6 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { ResolvePattern resolver (parent); - pattern->accept_vis (resolver); if (resolver.resolved_node == UNKNOWN_NODEID) { @@ -42,12 +41,10 @@ public: } }; - ~ResolvePattern () {} - void visit (AST::IdentifierPattern &pattern) override { - if (resolver->get_name_scope ().lookup (pattern.get_ident (), - &resolved_node)) + if (resolver->get_name_scope ().lookup ( + CanonicalPath (pattern.get_ident ()), &resolved_node)) { resolver->insert_resolved_name (pattern.get_node_id (), resolved_node); resolver->insert_new_definition (pattern.get_node_id (), @@ -68,23 +65,14 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { PatternDeclaration resolver (parent); - pattern->accept_vis (resolver); - if (resolver.resolved_node != UNKNOWN_NODEID) - { - // print both locations?! - rust_error_at (resolver.locus, "duplicate pattern %s", - pattern->as_string ().c_str ()); - } }; - ~PatternDeclaration () {} - void visit (AST::IdentifierPattern &pattern) override { // if we have a duplicate id this then allows for shadowing correctly // as new refs to this decl will match back here so it is ok to overwrite - resolver->get_name_scope ().insert (pattern.get_ident (), + resolver->get_name_scope ().insert (CanonicalPath (pattern.get_ident ()), pattern.get_node_id (), pattern.get_locus ()); resolver->insert_new_definition (pattern.get_node_id (), diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index afc0068..2550c39 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -32,17 +32,19 @@ class ResolveTopLevel : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::Item *item) + static void go (AST::Item *item, + const CanonicalPath &prefix = CanonicalPath::create_empty ()) { - ResolveTopLevel resolver; + ResolveTopLevel resolver (prefix); item->accept_vis (resolver); }; void visit (AST::TypeAlias &alias) override { resolver->get_type_scope ().insert ( - alias.get_new_type_name (), alias.get_node_id (), alias.get_locus (), - false, [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (alias.get_new_type_name ()), alias.get_node_id (), + alias.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (alias.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -51,9 +53,9 @@ public: void visit (AST::TupleStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -62,9 +64,9 @@ public: void visit (AST::StructStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -73,8 +75,9 @@ public: void visit (AST::StaticItem &var) override { resolver->get_name_scope ().insert ( - var.get_identifier (), var.get_node_id (), var.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (var.get_identifier ()), var.get_node_id (), + var.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (var.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -86,10 +89,11 @@ public: void visit (AST::ConstantItem &constant) override { + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - constant.get_identifier (), constant.get_node_id (), - constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -100,10 +104,11 @@ public: void visit (AST::Function &function) override { + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - function.get_function_name (), function.get_node_id (), - function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -122,13 +127,24 @@ public: void visit (AST::InherentImpl &impl_block) override { + bool canonicalize_type_args = !impl_block.has_generics (); + bool type_resolve_generic_args = false; + CanonicalPath impl_type + = ResolveTypeToCanonicalPath::resolve (*impl_block.get_type ().get (), + canonicalize_type_args, + type_resolve_generic_args); + CanonicalPath impl_prefix = prefix.append (impl_type); + for (auto &impl_item : impl_block.get_impl_items ()) - ResolveToplevelImplItem::go (impl_item.get (), - impl_block.get_type ().get ()); + ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); } private: - ResolveTopLevel () : ResolverBase (UNKNOWN_NODEID) {} + ResolveTopLevel (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) + {} + + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 9e7568e..35e04a8 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -25,73 +25,136 @@ namespace Rust { namespace Resolver { -class ResolveTypeToSimplePath : public ResolverBase +class ResolveConstantItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::ConstantItem &constant) + { + return CanonicalPath (constant.get_identifier ()); + } +}; + +class ResolveFunctionItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Function &function) + { + return CanonicalPath (function.get_function_name ()); + } +}; + +class ResolveMethodItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Method &method) + { + return CanonicalPath (method.get_method_name ()); + } +}; + +class ResolveTypeToCanonicalPath : public ResolverBase { using Rust::Resolver::ResolverBase::visit; public: - static bool go (AST::Type *type, AST::SimplePath &simple_path_result, - bool path_only = false) + static CanonicalPath resolve (AST::Type &type, + bool include_generic_args = true, + bool type_resolve_generic_args = true) { - ResolveTypeToSimplePath resolver (simple_path_result, path_only); - type->accept_vis (resolver); - return !resolver.type_seg_failed_flag; + ResolveTypeToCanonicalPath resolver (include_generic_args, + type_resolve_generic_args); + type.accept_vis (resolver); + return resolver.result; } void visit (AST::TypePath &path) override { - segs.reserve (path.get_num_segments ()); for (auto &seg : path.get_segments ()) { seg->accept_vis (*this); - if (type_seg_failed_flag) + if (failure_flag) return; } - - if (segs.empty ()) - { - rust_error_at (path.get_locus (), "failed to resolve path: %s", - path.as_string ().c_str ()); - return; - } - - bool has_opening_scope_res = false; - result = AST::SimplePath (std::move (segs), has_opening_scope_res, - path.get_locus ()); } void visit (AST::TypePathSegmentGeneric &seg) override; void visit (AST::TypePathSegment &seg) override; + static CanonicalPath canonicalize_generic_args (AST::GenericArgs &args); + + static bool type_resolve_generic_args (AST::GenericArgs &args); + private: - ResolveTypeToSimplePath (AST::SimplePath &simple_path_result, bool path_only) - : ResolverBase (UNKNOWN_NODEID), type_seg_failed_flag (false), - result (simple_path_result), path_only_flag (path_only) + ResolveTypeToCanonicalPath (bool include_generic_args, + bool type_resolve_generic_args) + : ResolverBase (UNKNOWN_NODEID), result (CanonicalPath::create_empty ()), + include_generic_args_flag (include_generic_args), + type_resolve_generic_args_flag (type_resolve_generic_args), + failure_flag (false) {} - bool type_seg_failed_flag; - std::vector segs; - AST::SimplePath &result; - bool path_only_flag; + CanonicalPath result; + bool include_generic_args_flag; + bool type_resolve_generic_args_flag; + bool failure_flag; +}; + +class ResolvePathSegmentToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::PathExprSegment &seg) + { + CanonicalPath path = CanonicalPath (seg.get_ident_segment ().as_string ()); + if (seg.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + seg.get_generic_args ()); + if (!ok) + { + rust_error_at (seg.get_locus (), + "failed to resolve all generic args"); + return CanonicalPath::create_empty (); + } + + path + = path.append (ResolveTypeToCanonicalPath::canonicalize_generic_args ( + seg.get_generic_args ())); + } + return path; + } }; -class ResolveTypePath +// FIXME: as part of imports and visibility we need to be able to keep a context +// for handling PathInExpressions segments as they can be local to a particular +// lexical scope requiring a context to be maintained for resolution +class ResolveRelativeTypePath { public: - static NodeId go (AST::TypePath &path, NodeId parent) + static NodeId go (AST::TypePath &path, NodeId parent, + const CanonicalPath &prefix, + bool canonicalize_type_with_generics) { - AST::SimplePath path_buffer = AST::SimplePath::create_empty (); - if (!ResolveTypeToSimplePath::go (&path, path_buffer)) - return UNKNOWN_NODEID; + CanonicalPath canonical_path + = ResolveTypeToCanonicalPath::resolve (path, + canonicalize_type_with_generics, + true); + if (canonical_path.is_error ()) + { + rust_error_at (path.get_locus (), "Failed to resolve canonical path"); + return UNKNOWN_NODEID; + } + + CanonicalPath lookup = canonical_path; + if (!prefix.is_error ()) + lookup = prefix.append (canonical_path); auto resolver = Resolver::get (); NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_type_scope ().lookup (path_buffer.as_string (), - &resolved_node)) + if (!resolver->get_type_scope ().lookup (canonical_path, &resolved_node)) { rust_error_at (path.get_locus_slow (), "failed to resolve TypePath: %s", - path_buffer.as_string ().c_str ()); + canonical_path.get ().c_str ()); return UNKNOWN_NODEID; } @@ -104,9 +167,10 @@ class ResolveType : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static NodeId go (AST::Type *type, NodeId parent) + static NodeId go (AST::Type *type, NodeId parent, + bool canonicalize_type_with_generics = false) { - ResolveType resolver (parent); + ResolveType resolver (parent, canonicalize_type_with_generics); type->accept_vis (resolver); if (!resolver.ok) rust_error_at (type->get_locus_slow (), "unresolved type"); @@ -139,7 +203,10 @@ public: void visit (AST::TypePath &path) override { - resolved_node = ResolveTypePath::go (path, parent); + resolved_node + = ResolveRelativeTypePath::go (path, parent, + CanonicalPath::create_empty (), + canonicalize_type_with_generics); ok = resolved_node != UNKNOWN_NODEID; if (ok) { @@ -160,12 +227,16 @@ public: type.get_type_referenced ()->accept_vis (*this); } - // nothing to do for inferred types void visit (AST::InferredType &type) override { ok = true; } private: - ResolveType (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveType (NodeId parent, bool canonicalize_type_with_generics) + : ResolverBase (parent), + canonicalize_type_with_generics (canonicalize_type_with_generics), + ok (false) + {} + bool canonicalize_type_with_generics; bool ok; }; @@ -190,9 +261,9 @@ public: // for now lets focus on handling the basics: like struct { a:T, ....} resolver->get_type_scope ().insert ( - param.get_type_representation (), param.get_node_id (), + CanonicalPath (param.get_type_representation ()), param.get_node_id (), param.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (param.get_locus (), "generic param redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -200,7 +271,11 @@ public: } private: - ResolveGenericParam (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveGenericParam (NodeId parent) + : ResolverBase (parent), + + ok (false) + {} bool ok; }; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 4cc1a93..aac55e2 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -50,7 +50,8 @@ Resolver::Resolver () : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()), name_scope (Scope (mappings->get_current_crate ())), type_scope (Scope (mappings->get_current_crate ())), - label_scope (Scope (mappings->get_current_crate ())) + label_scope (Scope (mappings->get_current_crate ())), + global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID) { generate_builtins (); } @@ -116,9 +117,12 @@ Resolver::insert_builtin_types (Rib *r) { auto builtins = get_builtin_types (); for (auto &builtin : builtins) - r->insert_name (builtin->as_string (), builtin->get_node_id (), - Linemap::predeclared_location (), false, - [] (std::string, NodeId, Location) -> void {}); + { + CanonicalPath builtin_path (builtin->as_string ()); + r->insert_name (builtin_path, builtin->get_node_id (), + Linemap::predeclared_location (), false, + [] (const CanonicalPath &, NodeId, Location) -> void {}); + } } std::vector & @@ -374,41 +378,84 @@ ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field) // rust-ast-resolve-type.h -void -ResolveTypeToSimplePath::visit (AST::TypePathSegmentGeneric &seg) +CanonicalPath +ResolveTypeToCanonicalPath::canonicalize_generic_args (AST::GenericArgs &args) { - if (!path_only_flag) + std::string buf; + + size_t i = 0; + size_t total = args.get_type_args ().size (); + + for (auto &ty_arg : args.get_type_args ()) { - AST::GenericArgs &generics = seg.get_generic_args (); - for (auto > : generics.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); + buf += ty_arg->as_string (); + if ((i + 1) < total) + buf += ","; + + i++; } + return CanonicalPath ("<" + buf + ">"); +} + +bool +ResolveTypeToCanonicalPath::type_resolve_generic_args (AST::GenericArgs &args) +{ + for (auto > : args.get_type_args ()) + { + ResolveType::go (gt.get (), UNKNOWN_NODEID); + // FIXME error handling here for inference variable since they do not have + // a node to resolve to + // if (resolved == UNKNOWN_NODEID) return false; + } + return true; +} + +void +ResolveTypeToCanonicalPath::visit (AST::TypePathSegmentGeneric &seg) +{ if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + // ident seg + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); + + // generic args + if (seg.has_generic_args ()) + { + if (include_generic_args_flag) + result + = result.append (canonicalize_generic_args (seg.get_generic_args ())); + + if (type_resolve_generic_args_flag) + { + bool ok = type_resolve_generic_args (seg.get_generic_args ()); + failure_flag = !ok; + } + } } void -ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) +ResolveTypeToCanonicalPath::visit (AST::TypePathSegment &seg) { if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); } // rust-ast-resolve-expr.h @@ -416,38 +463,77 @@ ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) void ResolvePath::resolve_path (AST::PathInExpression *expr) { - // this needs extended similar to the TypePath to lookup each segment - // in turn then look its rib for the next segment and so forth until we - // resolve to a final NodeId generic args can be ignored - std::string path_buf; - for (auto &seg : expr->get_segments ()) + // resolve root segment first then apply segments in turn + AST::PathExprSegment &root_segment = expr->get_segments ().at (0); + AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment (); + + bool segment_is_type = false; + CanonicalPath root_seg_path (root_ident_seg.as_string ()); + + // name scope first + if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node)) { - auto s = seg.get_ident_segment (); - if (s.is_error () && !seg.has_generic_args ()) + segment_is_type = false; + resolver->insert_resolved_name (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = true; + resolver->insert_resolved_type (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + else + { + rust_error_at (expr->get_locus (), + "unknown root segment in path %s lookup %s", + expr->as_string ().c_str (), + root_ident_seg.as_string ().c_str ()); + return; + } + + if (root_segment.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + root_segment.get_generic_args ()); + if (!ok) { - rust_error_at (expr->get_locus (), "malformed path"); + rust_error_at (root_segment.get_locus (), + "failed to resolve generic args"); return; } + } - if (seg.has_generic_args ()) - { - AST::GenericArgs &args = seg.get_generic_args (); - for (auto > : args.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); - } + if (expr->is_single_segment ()) + { + if (segment_is_type) + resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + else + resolver->insert_resolved_name (expr->get_node_id (), resolved_node); - if (!s.is_error ()) - { - bool needs_sep = !path_buf.empty (); - if (needs_sep) - path_buf += "::"; + resolver->insert_new_definition (expr->get_node_id (), + Definition{expr->get_node_id (), + parent}); + return; + } - path_buf += s.as_string (); - } + // we can attempt to resolve this path fully + CanonicalPath path = root_seg_path; + for (size_t i = 1; i < expr->get_segments ().size (); i++) + { + AST::PathExprSegment &seg = expr->get_segments ().at (i); + auto s = ResolvePathSegmentToCanonicalPath::resolve (seg); + path = path.append (s); } - // name scope first - if (resolver->get_name_scope ().lookup (path_buf, &resolved_node)) + if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_name (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -455,7 +541,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) parent}); } // check the type scope - else if (resolver->get_type_scope ().lookup (path_buf, &resolved_node)) + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_type (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -464,8 +550,42 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } else { - rust_error_at (expr->get_locus (), "unknown path %s lookup %s", - expr->as_string ().c_str (), path_buf.c_str ()); + // attempt to fully resolve the path which is allowed to fail given the + // following scenario + // + // https://github.com/Rust-GCC/gccrs/issues/355 Paths are + // resolved fully here, there are limitations though imagine: + // + // struct Foo (A); + // + // impl Foo { + // fn test() -> ... + // + // impl Foo { + // fn test() -> ... + // + // fn main() { + // let a:i32 = Foo::test(); + // + // there are multiple paths that test can resolve to Foo::::test here + // so we cannot resolve this case + // + // canonical names: + // + // struct Foo -> Foo + // impl Foo::fn test -> Foo::isize::test + // impl Foo::fn test -> Foo::f32::test + // + // Since there is the case we have the following paths for test: + // + // Foo::isize::test + // Foo::f32::test + // vs + // Foo::test + // + // but the lookup was simply Foo::test we must rely on type resolution to + // figure this type out in a similar fashion to method resolution with a + // probe phase } } diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h index b607fbe..13b6c91 100644 --- a/gcc/rust/resolve/rust-ast-verify-assignee.h +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -57,7 +57,8 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (!resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (!resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) return; ok = true; diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h index 9c01d47..205c877 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -26,6 +26,62 @@ namespace Rust { namespace Resolver { +// https://doc.rust-lang.org/reference/paths.html#canonical-paths +// +// struct X - path X +// impl X { fn test - path X::test } +// +// struct X - path X +// +// impl X { fn test - path X::test} +// impl X { fn test - path X::test } +// impl X { fn test - path X::test } +class CanonicalPath +{ +public: + explicit CanonicalPath (std::string path) : path (path) {} + + CanonicalPath (const CanonicalPath &other) : path (other.path) {} + + CanonicalPath &operator= (const CanonicalPath &other) + { + path = other.path; + return *this; + } + + std::string get () const { return path; } + + static CanonicalPath get_big_self () { return CanonicalPath ("Self"); } + + static CanonicalPath get_wee_self () { return CanonicalPath ("self"); } + + static CanonicalPath create_empty () + { + return CanonicalPath (std::string ()); + } + + bool is_error () const { return path.empty (); } + + CanonicalPath append (const CanonicalPath &other) const + { + rust_assert (!other.is_error ()); + return is_error () ? CanonicalPath (other.get ()) + : CanonicalPath (append (other.get ())); + } + + bool operator== (const CanonicalPath &b) const + { + return get ().compare (b.get ()) == 0; + } + + bool operator< (const CanonicalPath &b) const { return get () < b.get (); } + +private: + std::string append (std::string elem) const { return path + "::" + elem; } + + std::string path; +}; + class Rib { public: @@ -37,10 +93,11 @@ public: ~Rib () {} - void insert_name (std::string ident, NodeId id, Location locus, bool shadow, - std::function dup_cb) + void insert_name ( + const CanonicalPath &path, NodeId id, Location locus, bool shadow, + std::function dup_cb) { - auto it = mappings.find (ident); + auto it = mappings.find (path); bool already_exists = it != mappings.end (); if (already_exists && !shadow) { @@ -48,20 +105,20 @@ public: { if (decl.first == it->second) { - dup_cb (ident, it->second, decl.second); + dup_cb (path, it->second, decl.second); return; } } - dup_cb (ident, it->second, locus); + dup_cb (path, it->second, locus); return; } - mappings[ident] = id; + mappings[path] = id; decls_within_rib.insert (std::pair (id, locus)); references[id] = {}; } - bool lookup_name (std::string ident, NodeId *id) + bool lookup_name (const CanonicalPath &ident, NodeId *id) { auto it = mappings.find (ident); if (it == mappings.end ()) @@ -71,7 +128,7 @@ public: return true; } - void clear_name (std::string ident, NodeId id) + void clear_name (const CanonicalPath &ident, NodeId id) { mappings.erase (ident); for (auto &it : decls_within_rib) @@ -136,7 +193,7 @@ public: private: CrateNum crate_num; NodeId node_id; - std::map mappings; + std::map mappings; std::set > decls_within_rib; std::map > references; }; @@ -145,21 +202,24 @@ class Scope { public: Scope (CrateNum crate_num) : crate_num (crate_num) {} + ~Scope () {} - void insert (std::string ident, NodeId id, Location locus, bool shadow, - std::function dup_cb) + void + insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function dup_cb) { peek ()->insert_name (ident, id, locus, shadow, dup_cb); } - void insert (std::string ident, NodeId id, Location locus) + void insert (const CanonicalPath &ident, NodeId id, Location locus) { peek ()->insert_name (ident, id, locus, true, - [] (std::string, NodeId, Location) -> void {}); + [] (const CanonicalPath &, NodeId, Location) -> void { + }); } - bool lookup (std::string ident, NodeId *id) + bool lookup (const CanonicalPath &ident, NodeId *id) { NodeId lookup = UNKNOWN_NODEID; iterate ([&] (Rib *r) mutable -> bool { diff --git a/gcc/rust/typecheck/rust-hir-method-resolve.h b/gcc/rust/typecheck/rust-hir-method-resolve.h index ca5dbe5..35a5502 100644 --- a/gcc/rust/typecheck/rust-hir-method-resolve.h +++ b/gcc/rust/typecheck/rust-hir-method-resolve.h @@ -40,7 +40,8 @@ public: // lookup impl items for this crate and find all methods that can resolve to // this receiver probe.mappings->iterate_impl_items ( - [&] (HirId id, HIR::InherentImplItem *item) mutable -> bool { + [&] (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) mutable -> bool { item->accept_vis (probe); return true; }); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 6e7dff8..b946812 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -25,6 +25,7 @@ #include "rust-tyty-call.h" #include "rust-hir-type-check-struct-field.h" #include "rust-hir-method-resolve.h" +#include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" namespace Rust { @@ -171,8 +172,6 @@ public: { TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr (), false); - if (function_tyty == nullptr) - return; bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT || function_tyty->get_kind () == TyTy::TypeKind::FNDEF @@ -759,80 +758,93 @@ public: void visit (HIR::PathInExpression &expr) override { - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + // resolve root_segment + TyTy::BaseType *tyseg = resolve_root_path (expr); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + else if (expr.get_num_segments () == 1) + { + infered = tyseg; + return; + } - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + NodeId resolved_node_id = UNKNOWN_NODEID; + for (size_t i = 1; i < expr.get_num_segments (); i++) { - // these ref_node_ids will resolve to a pattern declaration but we are - // interested in the definition that this refers to get the parent id - Definition def; - if (!resolver->lookup_definition (ref_node_id, &def)) + HIR::PathExprSegment &seg = expr.get_segments ().at (i); + + // probe the path + auto candidates = PathProbeType::Probe (tyseg, seg.get_segment ()); + if (candidates.size () == 0) { - rust_error_at (expr.get_locus (), - "unknown reference for resolved name"); + rust_error_at (seg.get_locus (), "failed to resolve path segment"); + return; + } + else if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg.get_segment (), + seg.get_locus ()); return; } - ref_node_id = def.parent; - } - else if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup type reference for node: %s", - expr.as_string ().c_str ()); - return; - } - if (ref_node_id == UNKNOWN_NODEID) - { - rust_error_at (expr.get_locus (), "unresolved node: %s", - expr.as_string ().c_str ()); - return; - } + auto candidate = candidates.at (0); + tyseg = candidate.ty; + resolved_node_id + = candidate.impl_item->get_impl_mappings ().get_nodeid (); - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; + bool did_substitute = false; + if (seg.has_generic_args ()) + { + if (!tyseg->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + tyseg->as_string ().c_str ()); + return; + } + + did_substitute = true; + tyseg = SubstMapper::Resolve (tyseg, expr.get_locus (), + &seg.get_generic_args ()); + + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else + { + if (tyseg->needs_generic_substitutions ()) + { + did_substitute = true; + tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ()); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + } } - if (!context->lookup_type (ref, &infered)) + rust_assert (resolved_node_id != UNKNOWN_NODEID); + + // lookup if the name resolver was able to canonically resolve this or not + NodeId path_resolved_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "failed to resolve PathInExpression type"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!infered->supports_substitutions () && seg.has_generic_args ()) + // check the type scope + else if (resolver->lookup_resolved_type (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "path does not support substitutions"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - if (expr.is_self ()) - return; - - if (infered->has_subsititions_defined ()) + else { - if (!infered->can_substitute ()) - { - rust_error_at (expr.get_locus (), - "substitutions not supported for %s", - infered->as_string ().c_str ()); - return; - } - - infered = SubstMapper::Resolve (infered, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); } + + infered = tyseg; } void visit (HIR::LoopExpr &expr) override @@ -951,6 +963,75 @@ private: inside_loop (inside_loop) {} + TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr) + { + HIR::PathExprSegment &root = expr.get_root_seg (); + NodeId ast_node_id = root.get_mappings ().get_nodeid (); + + // then lookup the reference_node_id + NodeId ref_node_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + // these ref_node_ids will resolve to a pattern declaration but we are + // interested in the definition that this refers to get the parent id + Definition def; + if (!resolver->lookup_definition (ref_node_id, &def)) + { + rust_error_at (expr.get_locus (), + "unknown reference for resolved name"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + ref_node_id = def.parent; + } + else + { + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + } + + if (ref_node_id == UNKNOWN_NODEID) + { + rust_error_at (root.get_locus (), + "failed to type resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // node back to HIR + HirId ref; + if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), + ref_node_id, &ref)) + { + rust_error_at (expr.get_locus (), "reverse lookup failure"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + TyTy::BaseType *lookup = nullptr; + if (!context->lookup_type (ref, &lookup)) + { + rust_error_at (expr.get_locus (), "failed to resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // turbo-fish segment path:: + if (root.has_generic_args ()) + { + if (!lookup->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + lookup->as_string ().c_str ()); + return new TyTy::ErrorType (lookup->get_ref ()); + } + lookup = SubstMapper::Resolve (lookup, expr.get_locus (), + &root.get_generic_args ()); + } + else if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); + } + + return lookup; + } + bool validate_arithmetic_type (TyTy::BaseType *type, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 68becd4..e52368a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -58,7 +58,7 @@ public: { init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr (), inside_loop); - if (init_expr_ty == nullptr) + if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; init_expr_ty = init_expr_ty->clone (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index 3a6cdc7..8124f35 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -41,8 +41,6 @@ public: void visit (HIR::StructExprStructFields &struct_expr) override; - void visit (HIR::PathInExpression &path) override; - void visit (HIR::StructExprFieldIdentifierValue &field) override; void visit (HIR::StructExprFieldIndexValue &field) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 681fb24..6f6ab9c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -60,6 +60,7 @@ TypeResolution::Resolve (HIR::Crate &crate) // nothing to do if (ty->get_kind () != TyTy::TypeKind::INFER) return true; + TyTy::InferType *infer_var = (TyTy::InferType *) ty; TyTy::BaseType *default_type; bool ok = infer_var->default_type (&default_type); @@ -72,6 +73,7 @@ TypeResolution::Resolve (HIR::Crate &crate) UNKNOWN_LOCAL_DEFID), result); } + return true; }); @@ -161,14 +163,16 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) void TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) { - struct_expr.get_struct_name ().accept_vis (*this); - if (struct_path_resolved == nullptr) + TyTy::BaseType *struct_path_ty + = TypeCheckExpr::Resolve (&struct_expr.get_struct_name (), false); + if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT) { - rust_fatal_error (struct_expr.get_struct_name ().get_locus (), - "Failed to resolve type"); + rust_error_at (struct_expr.get_struct_name ().get_locus (), + "expected an ADT type for constructor"); return; } + struct_path_resolved = static_cast (struct_path_ty); TyTy::ADTType *struct_def = struct_path_resolved; if (struct_expr.has_struct_base ()) { @@ -292,78 +296,6 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) } void -TypeCheckStructExpr::visit (HIR::PathInExpression &expr) -{ - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); - - // then lookup the reference_node_id - NodeId ref_node_id; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup reference for node: %s", - expr.as_string ().c_str ()); - return; - } - } - - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; - } - - // the base reference for this name _must_ have a type set - TyTy::BaseType *lookup; - if (!context->lookup_type (ref, &lookup)) - { - rust_error_at (mappings->lookup_location (ref), - "consider giving this a type: %s", - expr.as_string ().c_str ()); - return; - } - - if (lookup->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected an ADT type"); - return; - } - - struct_path_resolved = static_cast (lookup); - if (struct_path_resolved->has_substitutions ()) - { - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!struct_path_resolved->needs_substitution () - && seg.has_generic_args ()) - { - rust_error_at (seg.get_generic_args ().get_locus (), - "unexpected type arguments"); - } - else if (struct_path_resolved->needs_substitution ()) - { - TyTy::BaseType *subst - = SubstMapper::Resolve (struct_path_resolved, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); - if (subst == nullptr || subst->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected a substituted ADT type"); - return; - } - struct_path_resolved = static_cast (subst); - } - } -} - -void TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) { auto it = fields_assigned.find (field.field_name); diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index d449c72..db43cbd 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -37,6 +37,11 @@ public: return mapper.resolved; } + static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus) + { + return SubstMapper::Resolve (base, locus, nullptr); + } + bool have_generic_args () const { return generics != nullptr; } void visit (TyTy::FnType &type) override diff --git a/gcc/testsuite/rust.test/compile/generics13.rs b/gcc/testsuite/rust.test/compile/generics13.rs new file mode 100644 index 0000000..03d6cee --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics13.rs @@ -0,0 +1,34 @@ +struct Foo { + a: A, +} + +struct GenericStruct { + a: T, + b: usize, +} + +impl Foo { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); + + let a2: GenericStruct; + a2 = GenericStruct:: { a: 1, b: 456 }; + + let b2: i8 = a2.a; + let c2: usize = a2.b; + + let a4; + a4 = GenericStruct { a: 1.0, b: 456 }; + + let b4: f32 = a4.a; + let c4: usize = a4.b; +} diff --git a/gcc/testsuite/rust.test/compile/generics14.rs b/gcc/testsuite/rust.test/compile/generics14.rs new file mode 100644 index 0000000..bf00f72 --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics14.rs @@ -0,0 +1,17 @@ +struct Foo { + a: A, +} + +impl Foo { + fn test() -> i32 { + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); +} diff --git a/gcc/testsuite/rust.test/xfail_compile/generics6.rs b/gcc/testsuite/rust.test/xfail_compile/generics6.rs new file mode 100644 index 0000000..256d2aa --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/generics6.rs @@ -0,0 +1,29 @@ +// { dg-excess-errors "Noisy error and debug" } +struct Foo { + a: A, +} + +impl Foo { + fn test() -> i32 { // {dg-error "possible candidate" } + 123 + } + + fn bar(self) -> isize { + self.a + } +} + +impl Foo { + fn test() -> i32 { // {dg-error "possible candidate" } + 123 + } + + fn bar(self) -> f32 { + self.a + } +} + +fn main() { + let a: i32 = Foo::test(); // { dg-error "multiple applicable items in scope for: test" } +} + diff --git a/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs new file mode 100644 index 0000000..3856b73 --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs @@ -0,0 +1,14 @@ +// { dg-excess-errors "Noisy error and debug" } +struct Foo(T, usize); + +impl Foo { + fn test() -> i32 { // { dg-error "was defined here" } + 123 + } + + fn test(self) -> i32 { // { dg-error "redefined multiple times" } + self.0 + } +} + +fn main() {} -- cgit v1.1 From 7e4ca97cac069886c2e54674f973f723e68ee912 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sat, 10 Apr 2021 17:40:32 +0100 Subject: Refactor Method resolution to take advantage of PathProbe This canonicalizes method resolution to the Path Probe used for Path expr resolution. So any errors will gain the same diagnostics. --- gcc/rust/typecheck/rust-hir-method-resolve.h | 79 +++++++-------------------- gcc/rust/typecheck/rust-hir-type-check-expr.h | 37 +++++++------ gcc/testsuite/rust.test/compile/generics15.rs | 21 +++++++ gcc/testsuite/rust.test/compile/generics16.rs | 29 ++++++++++ 4 files changed, 89 insertions(+), 77 deletions(-) create mode 100644 gcc/testsuite/rust.test/compile/generics15.rs create mode 100644 gcc/testsuite/rust.test/compile/generics16.rs (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-method-resolve.h b/gcc/rust/typecheck/rust-hir-method-resolve.h index 35a5502..b2391e3 100644 --- a/gcc/rust/typecheck/rust-hir-method-resolve.h +++ b/gcc/rust/typecheck/rust-hir-method-resolve.h @@ -22,6 +22,7 @@ #include "rust-hir-type-check-base.h" #include "rust-hir-full.h" #include "rust-tyty.h" +#include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" namespace Rust { @@ -32,74 +33,32 @@ class MethodResolution : public TypeCheckBase using Rust::Resolver::TypeCheckBase::visit; public: - static std::vector Probe (TyTy::BaseType *receiver, - HIR::PathExprSegment method_name) + static std::vector + Probe (std::vector &path_candidates) { - MethodResolution probe (receiver, method_name); - - // lookup impl items for this crate and find all methods that can resolve to - // this receiver - probe.mappings->iterate_impl_items ( - [&] (HirId id, HIR::InherentImplItem *item, - HIR::InherentImpl *impl) mutable -> bool { - item->accept_vis (probe); - return true; - }); - - return probe.probed; + MethodResolution probe; + for (auto &c : path_candidates) + probe.process_candidate (c); + + return probe.candidates; } - void visit (HIR::Method &method) override + void process_candidate (PathProbeCandidate &candidate) { - TyTy::BaseType *self_lookup = nullptr; - if (!context->lookup_type ( - method.get_self_param ().get_mappings ().get_hirid (), &self_lookup)) - { - rust_error_at (method.get_self_param ().get_locus (), - "failed to lookup lookup self type in MethodProbe"); - return; - } - - // are the names the same - HIR::PathIdentSegment seg = method_name.get_segment (); - if (seg.as_string ().compare (method.get_method_name ()) != 0) - { - // if the method name does not match then this is not a valid match - return; - } - - if (self_lookup->get_kind () != receiver->get_kind ()) - return; - - if (receiver->has_subsititions_defined () - != self_lookup->has_subsititions_defined ()) - return; - - if (self_lookup->has_subsititions_defined ()) - { - // we assume the receiver should be fully substituted at this stage - self_lookup = SubstMapperFromExisting::Resolve (receiver, self_lookup); - } - - if (!receiver->is_equal (*self_lookup)) - { - // incompatible self argument then this is not a valid method for this - // receiver - return; - } - - probed.push_back (&method); + is_method_flag = false; + candidate.impl_item->accept_vis (*this); + + if (is_method_flag) + candidates.push_back (candidate); } -private: - MethodResolution (TyTy::BaseType *receiver, HIR::PathExprSegment method_name) - : TypeCheckBase (), receiver (receiver), method_name (method_name) - {} + void visit (HIR::Method &method) override { is_method_flag = true; } - TyTy::BaseType *receiver; - HIR::PathExprSegment method_name; +private: + MethodResolution () : TypeCheckBase () {} - std::vector probed; + bool is_method_flag; + std::vector candidates; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index b946812..cb2f250 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -210,34 +210,37 @@ public: // which is simple. There will need to be adjustments to ensure we can turn // the receiver into borrowed references etc - auto probes - = MethodResolution::Probe (receiver_tyty, expr.get_method_name ()); - if (probes.size () == 0) + auto candidates + = PathProbeType::Probe (receiver_tyty, + expr.get_method_name ().get_segment ()); + if (candidates.size () == 0) { rust_error_at (expr.get_locus (), "failed to resolve the PathExprSegment to any Method"); return; } - else if (probes.size () > 1) + + // filter all methods + auto possible_methods = MethodResolution::Probe (candidates); + if (possible_methods.size () == 0) { - rust_error_at ( - expr.get_locus (), - "multiple candidates in MethodCallExpr have been probed is " - "not currently supported"); + rust_error_at (expr.get_method_name ().get_locus (), + "no method named %s found in scope", + expr.get_method_name ().as_string ().c_str ()); return; } - - auto resolved_method = probes.at (0); - TyTy::BaseType *lookup_tyty; - if (!context->lookup_type (resolved_method->get_mappings ().get_hirid (), - &lookup_tyty)) + else if (possible_methods.size () > 1) { - rust_error_at (resolved_method->get_locus (), - "failed to lookup type for CallExpr: %s", - expr.as_string ().c_str ()); + ReportMultipleCandidateError::Report ( + possible_methods, expr.get_method_name ().get_segment (), + expr.get_method_name ().get_locus ()); return; } + auto resolved_candidate = possible_methods.at (0); + HIR::InherentImplItem *resolved_method = resolved_candidate.impl_item; + TyTy::BaseType *lookup_tyty = resolved_candidate.ty; + TyTy::BaseType *lookup = lookup_tyty; if (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF) { @@ -270,7 +273,7 @@ public: // set up the resolved name on the path resolver->insert_resolved_name ( expr.get_mappings ().get_nodeid (), - resolved_method->get_mappings ().get_nodeid ()); + resolved_method->get_impl_mappings ().get_nodeid ()); // return the result of the function back infered = function_ret_tyty; diff --git a/gcc/testsuite/rust.test/compile/generics15.rs b/gcc/testsuite/rust.test/compile/generics15.rs new file mode 100644 index 0000000..adf02ee --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics15.rs @@ -0,0 +1,21 @@ +struct Foo(T, bool); + +impl Foo { + fn bar(self) -> i32 { + self.0 + } +} + +impl Foo { + fn bar(self) -> f32 { + self.0 + } +} + +fn main() { + let a = Foo(123, true); + let aa = a.bar(); + + let b = Foo(456f32, true); + let bb = b.bar(); +} diff --git a/gcc/testsuite/rust.test/compile/generics16.rs b/gcc/testsuite/rust.test/compile/generics16.rs new file mode 100644 index 0000000..1af24e0 --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics16.rs @@ -0,0 +1,29 @@ +struct Foo(T, bool); + +impl Foo { + fn new() -> Self { + Foo(123, true) + } + + fn bar(self) -> i32 { + self.0 + } +} + +impl Foo { + fn new() -> Self { + Foo(123f32, true) + } + + fn bar(self) -> f32 { + self.0 + } +} + +fn main() { + let a = Foo::::new(); + let aa: i32 = a.bar(); + + let b = Foo::::new(); + let bb: f32 = b.bar(); +} -- cgit v1.1 From 2f62f936aba0a712158e75f2556f0604cf7bb614 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 12 Apr 2021 18:06:32 +0100 Subject: Add check for duplicate overlapping impl-items When we have impl blocks for a generic type rust allows the programmer to reuse impl item names but if you give a generic implementation it means this generic implementation will overlap meaning it will not be possible to determine the Path. See rustc error: rustc --explain E0592 rustc_typeck/src/coherence/inherent_impls_overlap.rs Fixes #353 --- .../typecheck/rust-hir-inherent-impl-overlap.h | 220 +++++++++++++++++++++ gcc/rust/typecheck/rust-hir-type-check.cc | 5 + gcc/testsuite/rust.test/xfail_compile/generics7.rs | 27 +++ 3 files changed, 252 insertions(+) create mode 100644 gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h create mode 100644 gcc/testsuite/rust.test/xfail_compile/generics7.rs (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h new file mode 100644 index 0000000..b0071c3 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h @@ -0,0 +1,220 @@ +// Copyright (C) 2020 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-hir-full.h" + +namespace Rust { +namespace Resolver { + +class InherentImplItemToName : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static bool resolve (HIR::InherentImplItem *item, std::string &name_result) + { + InherentImplItemToName resolver (name_result); + item->accept_vis (resolver); + return resolver.ok; + } + + void visit (HIR::Method &method) override + { + ok = true; + result.assign (method.get_method_name ()); + } + + void visit (HIR::Function &function) override + { + ok = true; + result.assign (function.get_function_name ()); + } + + void visit (HIR::ConstantItem &constant) override + { + ok = true; + result.assign (constant.get_identifier ()); + } + +private: + InherentImplItemToName (std::string &result) + : TypeCheckBase (), ok (false), result (result) + {} + + bool ok; + std::string &result; +}; + +class GetLocusFromImplItem : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static bool Resolve (HIR::InherentImplItem *query, Location &locus) + { + GetLocusFromImplItem resolver (locus); + query->accept_vis (resolver); + return resolver.ok; + } + + void visit (HIR::ConstantItem &constant) override + { + ok = true; + locus = constant.get_locus (); + } + + void visit (HIR::Function &function) override + { + ok = true; + locus = function.get_locus (); + } + + void visit (HIR::Method &method) override + { + ok = true; + locus = method.get_locus (); + } + +private: + GetLocusFromImplItem (Location &locus) + : TypeCheckBase (), ok (false), locus (locus) + {} + + bool ok; + Location &locus; +}; + +class OverlappingImplItemPass : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static void go () + { + OverlappingImplItemPass pass; + + // generate mappings + pass.mappings->iterate_impl_items ([&] (HirId id, + HIR::InherentImplItem *impl_item, + HIR::InherentImpl *impl) -> bool { + pass.process_impl_item (id, impl_item, impl); + return true; + }); + + pass.scan (); + } + + void process_impl_item (HirId id, HIR::InherentImplItem *impl_item, + HIR::InherentImpl *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 = context->lookup_type (impl_type_id, &impl_type); + rust_assert (ok); + + std::string impl_item_name; + ok = InherentImplItemToName::resolve (impl_item, impl_item_name); + rust_assert (ok); + + 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)) + possible_collision (it->second, iy->second); + } + } + } + + void possible_collision ( + std::set > query, + std::set > candidate) + { + for (auto &q : query) + { + HIR::InherentImplItem *query_impl_item = q.first; + std::string query_impl_item_name = q.second; + + for (auto &c : candidate) + { + HIR::InherentImplItem *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::InherentImplItem *query, + HIR::InherentImplItem *dup, const std::string &name) + { + Location qlocus; + bool ok = GetLocusFromImplItem::Resolve (query, qlocus); + rust_assert (ok); + + Location dlocus; + ok = GetLocusFromImplItem::Resolve (dup, dlocus); + rust_assert (ok); + + // this needs GCC Rich locations see + // https://github.com/Rust-GCC/gccrs/issues/97 + rust_error_at (qlocus, "duplicate definitions with name %s", name.c_str ()); + rust_error_at (dlocus, "duplicate def associated with"); + } + +private: + OverlappingImplItemPass () : TypeCheckBase () {} + + std::map > > + impl_mappings; + + std::map > + possible_colliding_impls; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 6f6ab9c..c8394c8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-item.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-struct-field.h" +#include "rust-hir-inherent-impl-overlap.h" extern bool saw_errors (void); @@ -38,6 +39,10 @@ TypeResolution::Resolve (HIR::Crate &crate) if (saw_errors ()) return; + OverlappingImplItemPass::go (); + if (saw_errors ()) + return; + for (auto it = crate.items.begin (); it != crate.items.end (); it++) TypeCheckItem::Resolve (it->get ()); diff --git a/gcc/testsuite/rust.test/xfail_compile/generics7.rs b/gcc/testsuite/rust.test/xfail_compile/generics7.rs new file mode 100644 index 0000000..d8a9e93 --- /dev/null +++ b/gcc/testsuite/rust.test/xfail_compile/generics7.rs @@ -0,0 +1,27 @@ +// { dg-excess-errors "Noisy error and debug" } +struct Foo { + a: A, +} + +impl Foo { + fn bar(self) -> isize { // { dg-error "duplicate definitions with name bar" } + self.a + } +} + +impl Foo { + fn bar(self) -> char { // { dg-error "duplicate definitions with name bar" } + self.a + } +} + +impl Foo { + fn bar(self) -> T { + self.a + } +} + +fn main() { + let a = Foo { a: 123 }; + a.bar(); +} -- cgit v1.1 From 4ee35b6edb549be11571536bf78f8585a0282991 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Tue, 13 Apr 2021 09:46:41 +0100 Subject: Add missing dg-warning annotations Adding extra annotations means changes in compiler behaviour are caught faster so as to avoid regressions more aggressively. --- gcc/testsuite/rust.test/compile/generics13.rs | 6 ++++++ gcc/testsuite/rust.test/compile/generics14.rs | 2 ++ gcc/testsuite/rust.test/compile/generics15.rs | 2 ++ gcc/testsuite/rust.test/compile/generics16.rs | 2 ++ gcc/testsuite/rust.test/xfail_compile/redef_error6.rs | 5 +++-- 5 files changed, 15 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/rust.test/compile/generics13.rs b/gcc/testsuite/rust.test/compile/generics13.rs index 03d6cee..5c8795d 100644 --- a/gcc/testsuite/rust.test/compile/generics13.rs +++ b/gcc/testsuite/rust.test/compile/generics13.rs @@ -13,22 +13,28 @@ impl Foo { } fn bar(self) -> isize { + // { dg-warning "unused name" "" { target *-*-* } .-1 } self.a } } fn main() { let a: i32 = Foo::test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } let a2: GenericStruct; a2 = GenericStruct:: { a: 1, b: 456 }; let b2: i8 = a2.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } let c2: usize = a2.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } let a4; a4 = GenericStruct { a: 1.0, b: 456 }; let b4: f32 = a4.a; + // { dg-warning "unused name" "" { target *-*-* } .-1 } let c4: usize = a4.b; + // { dg-warning "unused name" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust.test/compile/generics14.rs b/gcc/testsuite/rust.test/compile/generics14.rs index bf00f72..aa8fbf2 100644 --- a/gcc/testsuite/rust.test/compile/generics14.rs +++ b/gcc/testsuite/rust.test/compile/generics14.rs @@ -8,10 +8,12 @@ impl Foo { } fn bar(self) -> isize { + // { dg-warning "unused name" "" { target *-*-* } .-1 } self.a } } fn main() { let a: i32 = Foo::test(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust.test/compile/generics15.rs b/gcc/testsuite/rust.test/compile/generics15.rs index adf02ee..c16a67c 100644 --- a/gcc/testsuite/rust.test/compile/generics15.rs +++ b/gcc/testsuite/rust.test/compile/generics15.rs @@ -15,7 +15,9 @@ impl Foo { fn main() { let a = Foo(123, true); let aa = a.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } let b = Foo(456f32, true); let bb = b.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust.test/compile/generics16.rs b/gcc/testsuite/rust.test/compile/generics16.rs index 1af24e0..15b9d7b 100644 --- a/gcc/testsuite/rust.test/compile/generics16.rs +++ b/gcc/testsuite/rust.test/compile/generics16.rs @@ -23,7 +23,9 @@ impl Foo { fn main() { let a = Foo::::new(); let aa: i32 = a.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } let b = Foo::::new(); let bb: f32 = b.bar(); + // { dg-warning "unused name" "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs index 3856b73..ef7e357 100644 --- a/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs +++ b/gcc/testsuite/rust.test/xfail_compile/redef_error6.rs @@ -2,11 +2,12 @@ struct Foo(T, usize); impl Foo { - fn test() -> i32 { // { dg-error "was defined here" } + fn test() -> i32 { 123 } - fn test(self) -> i32 { // { dg-error "redefined multiple times" } + fn test(self) -> i32 { + // { dg-error "redefined multiple times" "" { target *-*-* } .-1 } self.0 } } -- cgit v1.1