diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-07-14 20:48:41 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-14 20:48:41 +0000 |
commit | 089e62f33c328afea756ec4b92f5823584b08a3a (patch) | |
tree | 7dae8f29c3df18aa714c1e8ad931198634d93b81 | |
parent | 51f66ab1368fcd69ea1289bafae8f5eadda932dd (diff) | |
parent | 05b5eec7ab095d2d80a4fb8262c8985ad03550b6 (diff) | |
download | gcc-089e62f33c328afea756ec4b92f5823584b08a3a.zip gcc-089e62f33c328afea756ec4b92f5823584b08a3a.tar.gz gcc-089e62f33c328afea756ec4b92f5823584b08a3a.tar.bz2 |
Merge #566
566: Further error checking for trait impl blocks r=philberty a=philberty
This PR introduces enhanced type checking for trait constants
and associated types. It also brings in the check to ensure all
mandatory trait items are implemented. Note optional trait items
cannot be referenced or used yet and will be done in a separate PR.
Co-authored-by: Philip Herron <philip.herron@embecosm.com>
-rw-r--r-- | gcc/rust/ast/rust-item.h | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-item.h | 4 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-ref.h | 90 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-resolve.h | 103 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-implitem.h | 102 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-item.h | 58 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check.cc | 127 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits6.rs | 23 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits7.rs | 22 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/traits3.rs | 22 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/traits4.rs | 16 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/traits5.rs | 9 |
12 files changed, 402 insertions, 178 deletions
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 37d087c..30cab0e 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -3265,10 +3265,12 @@ public: std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + bool has_expr () const { return expr != nullptr; } + // TODO: is this better? Or is a "vis_block" better? std::unique_ptr<Expr> &get_expr () { - rust_assert (expr != nullptr); + rust_assert (has_expr ()); return expr; } diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 1f1ff30..0714f5d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -168,7 +168,9 @@ public: void visit (AST::TraitItemConst &constant) override { ResolveType::go (constant.get_type ().get (), constant.get_node_id ()); - ResolveExpr::go (constant.get_expr ().get (), constant.get_node_id ()); + + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr ().get (), constant.get_node_id ()); // the mutability checker needs to verify for immutable decls the number // of assignments are <1. This marks an implicit assignment diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 96498a5..35c0fef 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -27,6 +27,7 @@ namespace Resolver { // Data Objects for the associated trait items in a structure we can work with // https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html +class TypeCheckContext; class TraitItemReference { public: @@ -39,17 +40,11 @@ public: }; TraitItemReference (std::string identifier, bool optional, TraitItemType type, - const HIR::TraitItem *hir_trait_item, TyTy::BaseType *ty, - Location locus) - : identifier (identifier), optional_flag (optional), type (type), - hir_trait_item (hir_trait_item), ty (ty), locus (locus) - {} + HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions, + Location locus); - TraitItemReference (TraitItemReference const &other) - : identifier (other.identifier), optional_flag (other.optional_flag), - type (other.type), hir_trait_item (other.hir_trait_item), ty (other.ty), - locus (other.locus) - {} + TraitItemReference (TraitItemReference const &other); TraitItemReference &operator= (TraitItemReference const &other) { @@ -57,8 +52,13 @@ public: optional_flag = other.optional_flag; type = other.type; hir_trait_item = other.hir_trait_item; - ty = other.ty; + self = other.self; locus = other.locus; + context = other.context; + + inherited_substitutions.reserve (other.inherited_substitutions.size ()); + for (size_t i = 0; i < other.inherited_substitutions.size (); i++) + inherited_substitutions.push_back (other.inherited_substitutions.at (i)); return *this; } @@ -68,7 +68,8 @@ public: static TraitItemReference error () { - return TraitItemReference ("", false, ERROR, nullptr, nullptr, Location ()); + return TraitItemReference ("", false, ERROR, nullptr, nullptr, {}, + Location ()); } static TraitItemReference &error_node () @@ -82,7 +83,7 @@ public: std::string as_string () const { return "(" + trait_item_type_as_string (type) + " " + identifier + " " - + ty->as_string () + ")"; + + ")"; } static std::string trait_item_type_as_string (TraitItemType ty) @@ -109,17 +110,65 @@ public: const HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; } - TyTy::BaseType *get_tyty () const { return ty; } - Location get_locus () const { return locus; } + const Analysis::NodeMapping &get_mappings () const + { + return hir_trait_item->get_mappings (); + } + + TyTy::BaseType *get_tyty () const + { + rust_assert (hir_trait_item != nullptr); + + switch (type) + { + case CONST: + return get_type_from_constant ( + static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item)); + break; + + case TYPE: + return get_type_from_typealias ( + static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item)); + + case FN: + return get_type_from_fn ( + static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item)); + break; + + default: + return get_error (); + } + + gcc_unreachable (); + return get_error (); + } + private: + TyTy::ErrorType *get_error () const + { + return new TyTy::ErrorType (get_mappings ().get_hirid ()); + } + + TyTy::BaseType *get_type_from_typealias (/*const*/ + HIR::TraitItemType &type) const; + + TyTy::BaseType * + get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const; + + TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const; + std::string identifier; bool optional_flag; TraitItemType type; - const HIR::TraitItem *hir_trait_item; - TyTy::BaseType *ty; + HIR::TraitItem *hir_trait_item; + std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions; Location locus; + + TyTy::BaseType + *self; // this is the implict Self TypeParam required for methods + Resolver::TypeCheckContext *context; }; class TraitReference @@ -187,6 +236,13 @@ public: return TraitItemReference::error_node (); } + size_t size () const { return item_refs.size (); } + + const std::vector<TraitItemReference> &get_trait_items () const + { + return item_refs; + } + private: const HIR::Trait *hir_trait_ref; std::vector<TraitItemReference> item_refs; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 1b83be3..3de68c8 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -55,24 +55,11 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::TYPE, - &type, ty, locus); + &type, self, substitutions, locus); } void visit (HIR::TraitItemConst &cst) override { - // attempt to lookup the type of the trait item function - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (cst.get_mappings ().get_hirid (), &ty)) - { - auto resolved = TypeCheckType::Resolve (cst.get_type ().get ()); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (cst.get_locus (), - "failed to resolve trait constant type"); - return; - } - } - // create trait-item-ref Location locus = cst.get_locus (); bool is_optional = cst.has_expr (); @@ -80,95 +67,11 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::CONST, - &cst, ty, locus); + &cst, self, substitutions, locus); } void visit (HIR::TraitItemFunc &fn) override { - // FIXME this is duplicated in a few places and could be refactored - - // attempt to lookup the type of the trait item function - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (fn.get_mappings ().get_hirid (), &ty)) - { - HIR::TraitFunctionDecl &function = fn.get_decl (); - if (function.has_generics ()) - { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - // Skipping Lifetime completely until better handling. - break; - - case HIR::GenericParam::GenericKind::TYPE: { - auto param_type = TypeResolveGenericParam::Resolve ( - generic_param.get ()); - context->insert_type (generic_param->get_mappings (), - param_type); - - substitutions.push_back (TyTy::SubstitutionParamMapping ( - static_cast<HIR::TypeParam &> (*generic_param), - param_type)); - } - break; - } - } - } - - TyTy::BaseType *ret_type = nullptr; - if (!function.has_return_type ()) - ret_type = new TyTy::TupleType (fn.get_mappings ().get_hirid ()); - else - { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (fn.get_locus (), - "failed to resolve return type"); - return; - } - - ret_type = resolved->clone (); - ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); - } - - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - if (function.is_method ()) - { - // add the synthetic self param at the front, this is a placeholder - // for compilation to know parameter names. The types are ignored - // but we reuse the HIR identifier pattern which requires it - HIR::SelfParam &self_param = function.get_self (); - HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern ( - "self", self_param.get_locus (), self_param.is_ref (), - self_param.is_mut (), std::unique_ptr<HIR::Pattern> (nullptr)); - context->insert_type (self_param.get_mappings (), self->clone ()); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, - self->clone ())); - } - - for (auto ¶m : function.get_function_params ()) - { - // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ()); - params.push_back (std::pair<HIR::Pattern *, TyTy::BaseType *> ( - param.get_param_name (), param_tyty)); - - context->insert_type (param.get_mappings (), param_tyty); - } - - ty = new TyTy::FnType (fn.get_mappings ().get_hirid (), - function.get_function_name (), - function.is_method (), std::move (params), - ret_type, std::move (substitutions)); - context->insert_type (fn.get_mappings (), ty); - } - // create trait-item-ref Location locus = fn.get_locus (); bool is_optional = fn.has_block_defined (); @@ -176,7 +79,7 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::FN, &fn, - ty, locus); + self, substitutions, locus); } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index b0264e5..d6c3aed 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -214,116 +214,109 @@ public: void visit (HIR::ConstantItem &constant) override { - TypeCheckImplItem::visit (constant); - - // we get the error checking from the base method here - TyTy::BaseType *lookup; - if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup)) - return; - - const TraitItemReference &trait_item_ref - = trait_reference.lookup_trait_item ( - constant.get_identifier (), TraitItemReference::TraitItemType::CONST); + resolved_trait_item = trait_reference.lookup_trait_item ( + constant.get_identifier (), TraitItemReference::TraitItemType::CONST); // unknown trait item - if (trait_item_ref.is_error ()) + if (resolved_trait_item.is_error ()) { RichLocation r (constant.get_locus ()); r.add_range (trait_reference.get_locus ()); rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>", constant.get_identifier ().c_str (), trait_reference.get_name ().c_str ()); - return; } + // normal resolution of the item + TypeCheckImplItem::visit (constant); + TyTy::BaseType *lookup; + if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup)) + return; + if (resolved_trait_item.is_error ()) + return; + // check the types are compatible - if (!trait_item_ref.get_tyty ()->can_eq (lookup, true)) + if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true)) { RichLocation r (constant.get_locus ()); - r.add_range (trait_item_ref.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); rust_error_at ( r, "constant %<%s%> has an incompatible type for trait %<%s%>", constant.get_identifier ().c_str (), trait_reference.get_name ().c_str ()); - return; } - - resolved_trait_item = trait_item_ref; } void visit (HIR::TypeAlias &type) override { - TypeCheckImplItem::visit (type); - - // we get the error checking from the base method here - TyTy::BaseType *lookup; - if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup)) - return; - - const TraitItemReference &trait_item_ref - = trait_reference.lookup_trait_item ( - type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE); + resolved_trait_item = trait_reference.lookup_trait_item ( + type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE); // unknown trait item - if (trait_item_ref.is_error ()) + if (resolved_trait_item.is_error ()) { RichLocation r (type.get_locus ()); r.add_range (trait_reference.get_locus ()); rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>", type.get_new_type_name ().c_str (), trait_reference.get_name ().c_str ()); - return; } + // normal resolution of the item + TypeCheckImplItem::visit (type); + TyTy::BaseType *lookup; + if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup)) + return; + if (resolved_trait_item.is_error ()) + return; + // check the types are compatible - if (!trait_item_ref.get_tyty ()->can_eq (lookup, true)) + if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true)) { RichLocation r (type.get_locus ()); - r.add_range (trait_item_ref.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); rust_error_at ( r, "type alias %<%s%> has an incompatible type for trait %<%s%>", type.get_new_type_name ().c_str (), trait_reference.get_name ().c_str ()); - return; } - resolved_trait_item = trait_item_ref; + context->insert_type (resolved_trait_item.get_mappings (), + lookup->clone ()); } void visit (HIR::Function &function) override { - TypeCheckImplItem::visit (function); - - // we get the error checking from the base method here - TyTy::BaseType *lookup; - if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) - return; - - if (lookup->get_kind () != TyTy::TypeKind::FNDEF) - return; - - TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); - const TraitItemReference &trait_item_ref - = trait_reference.lookup_trait_item ( - fntype->get_identifier (), TraitItemReference::TraitItemType::FN); + resolved_trait_item = trait_reference.lookup_trait_item ( + function.get_function_name (), TraitItemReference::TraitItemType::FN); // unknown trait item - if (trait_item_ref.is_error ()) + if (resolved_trait_item.is_error ()) { RichLocation r (function.get_locus ()); r.add_range (trait_reference.get_locus ()); rust_error_at (r, "method %<%s%> is not a member of trait %<%s%>", - fntype->get_identifier ().c_str (), + function.get_function_name ().c_str (), trait_reference.get_name ().c_str ()); - return; } - rust_assert (trait_item_ref.get_tyty ()->get_kind () + // we get the error checking from the base method here + TypeCheckImplItem::visit (function); + TyTy::BaseType *lookup; + if (!context->lookup_type (function.get_mappings ().get_hirid (), &lookup)) + return; + if (resolved_trait_item.is_error ()) + return; + + rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); + rust_assert (resolved_trait_item.get_tyty ()->get_kind () == TyTy::TypeKind::FNDEF); + + TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); TyTy::FnType *trait_item_fntype - = static_cast<TyTy::FnType *> (trait_item_ref.get_tyty ()); + = static_cast<TyTy::FnType *> (resolved_trait_item.get_tyty ()); // sets substitute self into the trait_item_ref->tyty TyTy::SubstitutionParamMapping *self_mapping = nullptr; @@ -350,16 +343,13 @@ public: if (!trait_item_fntype->can_eq (fntype, true)) { RichLocation r (function.get_locus ()); - r.add_range (trait_item_ref.get_locus ()); + r.add_range (resolved_trait_item.get_locus ()); rust_error_at ( r, "method %<%s%> has an incompatible type for trait %<%s%>", fntype->get_identifier ().c_str (), trait_reference.get_name ().c_str ()); - return; } - - resolved_trait_item = trait_item_ref; } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 0126ded..f1ae82d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -60,13 +60,65 @@ public: return; } + bool is_trait_impl_block = !trait_reference.is_error (); + + std::vector<std::reference_wrapper<const TraitItemReference>> + trait_item_refs; for (auto &impl_item : impl_block.get_impl_items ()) { - if (trait_reference.is_error ()) + if (!is_trait_impl_block) TypeCheckImplItem::Resolve (impl_item.get (), self); else - TypeCheckImplItemWithTrait::Resolve (impl_item.get (), self, - trait_reference); + { + auto &trait_item_ref + = TypeCheckImplItemWithTrait::Resolve (impl_item.get (), self, + trait_reference); + trait_item_refs.push_back (trait_item_ref); + } + } + + bool impl_block_missing_trait_items + = is_trait_impl_block + && trait_reference.size () != trait_item_refs.size (); + if (impl_block_missing_trait_items) + { + // filter the missing impl_items + std::vector<std::reference_wrapper<const TraitItemReference>> + missing_trait_items; + for (auto &trait_item_ref : trait_reference.get_trait_items ()) + { + bool found = false; + for (const TraitItemReference &implemented_trait_item : + trait_item_refs) + { + std::string trait_item_name = trait_item_ref.get_identifier (); + std::string impl_item_name + = implemented_trait_item.get_identifier (); + found = trait_item_name.compare (impl_item_name) == 0; + if (found) + break; + } + + bool is_required_trait_item = !trait_item_ref.is_optional (); + if (!found && is_required_trait_item) + missing_trait_items.push_back (trait_item_ref); + } + + std::string missing_items_buf; + RichLocation r (impl_block.get_locus ()); + for (size_t i = 0; i < missing_trait_items.size (); i++) + { + bool has_more = (i + 1) < missing_trait_items.size (); + const TraitItemReference &missing_trait_item + = missing_trait_items.at (i); + missing_items_buf + += missing_trait_item.get_identifier () + (has_more ? ", " : ""); + r.add_range (missing_trait_item.get_locus ()); + } + + rust_error_at (r, "missing %s in implementation of trait %<%s%>", + missing_items_buf.c_str (), + trait_reference.get_name ().c_str ()); } } diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index d21fb3d..acfc022 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -375,5 +375,132 @@ TypeCheckType::visit (HIR::ArrayType &type) TyTy::TyVar (base->get_ref ())); } +// rust-hir-trait-ref.h + +TraitItemReference::TraitItemReference ( + std::string identifier, bool optional, TraitItemType type, + HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions, Location locus) + : identifier (identifier), optional_flag (optional), type (type), + hir_trait_item (hir_trait_item), inherited_substitutions (substitutions), + locus (locus), self (self), context (TypeCheckContext::get ()) +{} + +TraitItemReference::TraitItemReference (TraitItemReference const &other) + : identifier (other.identifier), optional_flag (other.optional_flag), + type (other.type), hir_trait_item (other.hir_trait_item), + locus (other.locus), self (other.self), context (TypeCheckContext::get ()) +{ + inherited_substitutions.reserve (other.inherited_substitutions.size ()); + for (size_t i = 0; i < other.inherited_substitutions.size (); i++) + inherited_substitutions.push_back (other.inherited_substitutions.at (i)); +} + +TyTy::BaseType * +TraitItemReference::get_type_from_typealias (/*const*/ + HIR::TraitItemType &type) const +{ + TyTy::TyVar var (get_mappings ().get_hirid ()); + return var.get_tyty (); +} + +TyTy::BaseType * +TraitItemReference::get_type_from_constant ( + /*const*/ HIR::TraitItemConst &constant) const +{ + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); + if (constant.has_expr ()) + { + TyTy::BaseType *expr + = TypeCheckExpr::Resolve (constant.get_expr ().get (), false); + + return type->unify (expr); + } + return type; +} + +TyTy::BaseType * +TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions + = inherited_substitutions; + + HIR::TraitFunctionDecl &function = fn.get_decl (); + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + // Skipping Lifetime completely until better handling. + break; + + case HIR::GenericParam::GenericKind::TYPE: { + auto param_type + = TypeResolveGenericParam::Resolve (generic_param.get ()); + context->insert_type (generic_param->get_mappings (), + param_type); + + substitutions.push_back (TyTy::SubstitutionParamMapping ( + static_cast<HIR::TypeParam &> (*generic_param), param_type)); + } + break; + } + } + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_return_type ()) + ret_type = new TyTy::TupleType (fn.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (fn.get_locus (), "failed to resolve return type"); + return get_error (); + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + if (function.is_method ()) + { + // add the synthetic self param at the front, this is a placeholder + // for compilation to know parameter names. The types are ignored + // but we reuse the HIR identifier pattern which requires it + HIR::SelfParam &self_param = function.get_self (); + HIR::IdentifierPattern *self_pattern + = new HIR::IdentifierPattern ("self", self_param.get_locus (), + self_param.is_ref (), + self_param.is_mut (), + std::unique_ptr<HIR::Pattern> (nullptr)); + context->insert_type (self_param.get_mappings (), self->clone ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, + self->clone ())); + } + + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + } + + return new TyTy::FnType (fn.get_mappings ().get_hirid (), + function.get_function_name (), function.is_method (), + std::move (params), ret_type, substitutions); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/testsuite/rust/compile/torture/traits6.rs b/gcc/testsuite/rust/compile/torture/traits6.rs new file mode 100644 index 0000000..5aae2e3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits6.rs @@ -0,0 +1,23 @@ +trait Foo { + type A; + // { dg-warning "unused name .Foo::A." "" { target *-*-* } .-1 } + + fn baz(a: Self::A) -> Self::A; + // { dg-warning "unused name .a." "" { target *-*-* } .-1 } + // { dg-warning "unused name .Foo::baz." "" { target *-*-* } .-2 } +} + +struct Bar<T>(T); + +impl<T> Foo for Bar<T> { + type A = T; + + fn baz(a: Self::A) -> T { + a + } +} + +fn main() { + let a; + a = Bar::<i32>::baz(123); +} diff --git a/gcc/testsuite/rust/compile/torture/traits7.rs b/gcc/testsuite/rust/compile/torture/traits7.rs new file mode 100644 index 0000000..a6fe5a3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits7.rs @@ -0,0 +1,22 @@ +trait Foo { + const A: i32; + // { dg-warning "unused name .Foo::A." "" { target *-*-* } .-1 } + + fn test(self); + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .Foo::test." "" { target *-*-* } .-2 } +} + +struct Bar; +impl Foo for Bar { + const A: i32 = 123; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn test(self) {} + // { dg-warning "unused name" "" { target *-*-* } .-1 } +} + +fn main() { + let a = Bar; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/traits3.rs b/gcc/testsuite/rust/compile/traits3.rs new file mode 100644 index 0000000..c971a11 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits3.rs @@ -0,0 +1,22 @@ +trait Foo { + type A; + + fn baz(a: Self::A) -> Self::A; +} + +struct Bar<T>(T); + +impl<T> Foo for Bar<T> { + type A = i32; + + fn baz(a: f32) -> f32 { + // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 } + // { dg-error "method .baz. has an incompatible type for trait .Foo." "" { target *-*-* } .-2 } + a + } +} + +fn main() { + let a; + a = Bar::<i32>::baz(123f32); +} diff --git a/gcc/testsuite/rust/compile/traits4.rs b/gcc/testsuite/rust/compile/traits4.rs new file mode 100644 index 0000000..486301d --- /dev/null +++ b/gcc/testsuite/rust/compile/traits4.rs @@ -0,0 +1,16 @@ +trait Foo { + const A: i32; + + fn test(self); +} + +struct Bar; +impl Foo for Bar { + // { dg-error "missing A in implementation of trait .Foo." "" { target *-*-* } .-1 } + fn test(self) {} +} + +fn main() { + let a = Bar; + a.test(); +} diff --git a/gcc/testsuite/rust/compile/traits5.rs b/gcc/testsuite/rust/compile/traits5.rs new file mode 100644 index 0000000..8b2fb9b --- /dev/null +++ b/gcc/testsuite/rust/compile/traits5.rs @@ -0,0 +1,9 @@ +trait Foo { + const A: i32; + + fn test(self); +} + +struct Bar; +impl Foo for Bar {} +// { dg-error "missing A, test in implementation of trait .Foo." "" { target *-*-* } .-1 } |