https://gcc.gnu.org/g:91126cb80e3dd8bad846461088c948c2b797dccc
commit r16-2986-g91126cb80e3dd8bad846461088c948c2b797dccc Author: Philip Herron <herron.phi...@googlemail.com> Date: Sun Jul 27 21:47:54 2025 +0100 gccrs: Add initial support for const generics In order to support const generics we map the declarations to a ConstType this means we reuse all our existing type coercion, unification code and generic substitutions code to support this with minimal impact. This patch adds support for: 1. Default const generics 2. Infer const generics 3. ADTType suport 4. unconstrained checks 5. ensure types of the const generic and default 6. validation if passing a const argument to a type argument Lots of test cases now work and new ones added. More work is needed to support this on functions and method resolution of impls like Foo<1> vs Foo<2> once thats in we can look to support some of the const generic array impls next. gcc/rust/ChangeLog: * backend/rust-compile-base.cc: useful debug * backend/rust-compile-stmt.cc (CompileStmt::visit): likewise * backend/rust-compile-type.cc (TyTyResolveCompile::visit): fold the capacity into ConstType * hir/tree/rust-hir-generic-param.h: make const * hir/tree/rust-hir-path.h: take into account const arguments now * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_literal): needs const * typecheck/rust-hir-type-check-base.h: add error handling for const supported locations * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): const type the arrays * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::visit): update (TypeCheckImplItem::visit): likewise * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): likewise (TypeCheckItem::resolve_impl_block_substitutions): likewise * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): wrap up const type * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise (TypeResolveGenericParam::visit): likewise (TypeResolveGenericParam::apply_trait_bounds): remove HIR::Generic from Param * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): cleanup * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::SubstitutionParamMapping): handle const generics (SubstitutionParamMapping::get_type_representation): likewise (SubstitutionParamMapping::param_has_default_ty): likewise (SubstitutionParamMapping::get_default_ty): likewise (SubstitutionRef::infer_substitions): likewise * typecheck/rust-tyty-subst.h: likewise * typecheck/rust-tyty-util.cc (TyVar::get_implicit_const_infer_var): new helper * typecheck/rust-tyty-util.h (class ConstType): likewise * typecheck/rust-tyty.cc (BaseType::is_concrete): check for array const concrete (ArrayType::as_string): update to const (ArrayType::handle_substitions): likewise (ParamType::ParamType): likewise (ParamType::get_generic_param): likewise (ParamType::clone): likewise (ConstType::ConstType): likewise (ConstType::set_value): likewise (ConstType::clone): likewise (ConstType::get_generic_param): likewise (generate_tree_str): new helper to pretty print gimple (ConstType::get_name): uses the generate_tree_str (ConstType::handle_substitions): handle const infer's * typecheck/rust-tyty.h (RUST_TYTY): likewise * typecheck/rust-unify.cc (UnifyRules::expect_array): likewise (UnifyRules::expect_const): likewise gcc/testsuite/ChangeLog: * rust/compile/const_generics_3.rs: this works now * rust/compile/const_generics_5.rs: likewise * rust/compile/const_generics_8.rs: move the failure to another test case * rust/compile/const_generics_10.rs: New test. * rust/compile/const_generics_11.rs: New test. * rust/compile/const_generics_12.rs: New test. * rust/compile/const_generics_13.rs: New test. * rust/compile/const_generics_14.rs: New test. * rust/compile/const_generics_15.rs: New test. * rust/compile/const_generics_16.rs: New test. * rust/compile/const_generics_9.rs: New test. Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/backend/rust-compile-base.cc | 3 + gcc/rust/backend/rust-compile-stmt.cc | 3 + gcc/rust/backend/rust-compile-type.cc | 3 +- gcc/rust/hir/tree/rust-hir-generic-param.h | 4 +- gcc/rust/hir/tree/rust-hir-path.h | 4 +- gcc/rust/typecheck/rust-hir-type-check-base.cc | 71 +++++++++-- gcc/rust/typecheck/rust-hir-type-check-base.h | 2 + gcc/rust/typecheck/rust-hir-type-check-expr.cc | 22 ++-- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 11 +- gcc/rust/typecheck/rust-hir-type-check-item.cc | 23 ++-- gcc/rust/typecheck/rust-hir-type-check-pattern.cc | 3 +- gcc/rust/typecheck/rust-hir-type-check-type.cc | 49 +++++--- gcc/rust/typecheck/rust-hir-type-check.cc | 4 +- gcc/rust/typecheck/rust-tyty-subst.cc | 140 ++++++++++++++++++--- gcc/rust/typecheck/rust-tyty-subst.h | 4 +- gcc/rust/typecheck/rust-tyty-util.cc | 34 +++-- gcc/rust/typecheck/rust-tyty-util.h | 4 + gcc/rust/typecheck/rust-tyty.cc | 119 ++++++++++++------ gcc/rust/typecheck/rust-tyty.h | 24 ++-- gcc/rust/typecheck/rust-unify.cc | 80 ++++++++++-- gcc/testsuite/rust/compile/const_generics_10.rs | 32 +++++ gcc/testsuite/rust/compile/const_generics_11.rs | 14 +++ gcc/testsuite/rust/compile/const_generics_12.rs | 14 +++ gcc/testsuite/rust/compile/const_generics_13.rs | 11 ++ gcc/testsuite/rust/compile/const_generics_14.rs | 13 ++ gcc/testsuite/rust/compile/const_generics_15.rs | 16 +++ gcc/testsuite/rust/compile/const_generics_16.rs | 10 ++ gcc/testsuite/rust/compile/const_generics_3.rs | 25 ++-- gcc/testsuite/rust/compile/const_generics_5.rs | 4 +- gcc/testsuite/rust/compile/const_generics_8.rs | 7 +- gcc/testsuite/rust/compile/const_generics_9.rs | 13 ++ 31 files changed, 609 insertions(+), 157 deletions(-) diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 8994520f16d5..73c34b269b7e 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -696,6 +696,9 @@ HIRCompileBase::compile_function ( std::string ir_symbol_name = canonical_path.get () + fntype->subst_as_string (); + rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (), + fntype->get_name ().c_str ()); + // we don't mangle the main fn since we haven't implemented the main shim bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item && canonical_path.size () <= 2; diff --git a/gcc/rust/backend/rust-compile-stmt.cc b/gcc/rust/backend/rust-compile-stmt.cc index a4b5a989fc47..b520baf9ab8c 100644 --- a/gcc/rust/backend/rust-compile-stmt.cc +++ b/gcc/rust/backend/rust-compile-stmt.cc @@ -58,6 +58,9 @@ CompileStmt::visit (HIR::LetStmt &stmt) return; } + rust_debug_loc (stmt.get_locus (), " -> LetStmt %s", + ty->as_string ().c_str ()); + // setup var decl nodes fncontext fnctx = ctx->peek_fn (); tree fndecl = fnctx.fndecl; diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 2058ccd3aea8..0622954b2a28 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -476,7 +476,8 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); - tree folded_capacity_expr = type.get_capacity (); + TyTy::ConstType *const_capacity = type.get_capacity (); + tree folded_capacity_expr = const_capacity->get_value (); // build_index_type takes the maximum index, which is one less than // the length. diff --git a/gcc/rust/hir/tree/rust-hir-generic-param.h b/gcc/rust/hir/tree/rust-hir-generic-param.h index 960de565c142..340b5c61ead3 100644 --- a/gcc/rust/hir/tree/rust-hir-generic-param.h +++ b/gcc/rust/hir/tree/rust-hir-generic-param.h @@ -150,7 +150,7 @@ public: location_t get_locus () const override final { return locus; }; - bool has_default_expression () { return default_expression != nullptr; } + bool has_default_expression () const { return default_expression != nullptr; } std::string get_name () { return name; } Type &get_type () @@ -160,6 +160,8 @@ public: } Expr &get_default_expression () { return *default_expression; } + const Expr &get_default_expression () const { return *default_expression; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 5f88c6827bb1..4f296d868b49 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -132,6 +132,8 @@ public: std::unique_ptr<Expr> &get_expression () { return expression; } + location_t get_locus () const { return locus; } + private: std::unique_ptr<Expr> expression; location_t locus; @@ -150,7 +152,7 @@ public: bool has_generic_args () const { return !(lifetime_args.empty () && type_args.empty () - && binding_args.empty ()); + && binding_args.empty () && const_args.empty ()); } GenericArgs (std::vector<Lifetime> lifetime_args, diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index cbb85bd4f4f3..5c7690a6e76d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -18,12 +18,14 @@ #include "rust-hir-type-check-base.h" #include "rust-compile-base.h" +#include "rust-hir-item.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-resolve.h" #include "rust-type-util.h" #include "rust-attribute-values.h" #include "rust-tyty.h" +#include "tree.h" namespace Rust { namespace Resolver { @@ -34,12 +36,14 @@ TypeCheckBase::TypeCheckBase () void TypeCheckBase::ResolveGenericParams ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi) { TypeCheckBase ctx; - ctx.resolve_generic_params (generic_params, substitutions, is_foreign, abi); + ctx.resolve_generic_params (item_kind, item_locus, generic_params, + substitutions, is_foreign, abi); } static void @@ -291,9 +295,18 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, auto ctx = Compile::Context::get (); tree capacity = Compile::HIRCompileBase::query_compile_const_expr ( ctx, expected_ty, *literal_capacity); + + TyTy::ConstType *capacity_expr + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + expected_ty, capacity, {}, + literal_capacity->get_locus (), + literal_capacity->get_mappings ().get_hirid (), + literal_capacity->get_mappings ().get_hirid (), + {}); + TyTy::ArrayType *array - = new TyTy::ArrayType (array_mapping.get_hirid (), locus, capacity, - TyTy::TyVar (u8->get_ref ())); + = new TyTy::ArrayType (array_mapping.get_hirid (), locus, + capacity_expr, TyTy::TyVar (u8->get_ref ())); context->insert_type (array_mapping, array); infered = new TyTy::ReferenceType (expr_mappings.get_hirid (), @@ -442,6 +455,7 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) void TypeCheckBase::resolve_generic_params ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi) @@ -474,6 +488,27 @@ TypeCheckBase::resolve_generic_params ( if (param.has_default_expression ()) { + switch (item_kind) + { + case HIR::Item::ItemKind::Struct: + case HIR::Item::ItemKind::Enum: + case HIR::Item::ItemKind::TypeAlias: + case HIR::Item::ItemKind::Trait: + case HIR::Item::ItemKind::Union: + break; + + default: + { + rich_location r (line_table, item_locus); + r.add_fixit_remove (param.get_locus ()); + rust_error_at ( + r, + "default values for const generic parameters are not " + "allowed here"); + } + break; + } + auto expr_type = TypeCheckExpr::Resolve (param.get_default_expression ()); @@ -483,14 +518,34 @@ TypeCheckBase::resolve_generic_params ( expr_type, param.get_default_expression ().get_locus ()), param.get_locus ()); + + // fold the default value + auto ctx = Compile::Context::get (); + auto &expr = param.get_default_expression (); + tree default_value + = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, specified_type, expr); + + TyTy::ConstType *default_const_decl + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + param.get_name (), specified_type, + default_value, {}, param.get_locus (), + expr.get_mappings ().get_hirid (), + expr.get_mappings ().get_hirid (), {}); + + context->insert_type (expr.get_mappings (), default_const_decl); } - context->insert_type (generic_param->get_mappings (), - specified_type); + TyTy::ConstType *const_decl + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Decl, + param.get_name (), specified_type, + error_mark_node, {}, param.get_locus (), + param.get_mappings ().get_hirid (), + param.get_mappings ().get_hirid (), {}); - // TODO for const generics - // TyTy::SubstitutionParamMapping p (*generic_param, param_type); - // substitutions.push_back (p); + context->insert_type (generic_param->get_mappings (), const_decl); + TyTy::SubstitutionParamMapping p (*generic_param, const_decl); + substitutions.push_back (p); } break; diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index fc55516fab10..5934e57727f7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -33,6 +33,7 @@ public: virtual ~TypeCheckBase () {} static void ResolveGenericParams ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi); @@ -61,6 +62,7 @@ protected: location_t locus); void resolve_generic_params ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign = false, ABI abi = ABI::RUST); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 4a105e77d919..92912e835ad0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -33,6 +33,7 @@ #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" #include "rust-compile-base.h" +#include "tree.h" namespace Rust { namespace Resolver { @@ -1058,6 +1059,10 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) { auto &elements = expr.get_internal_elements (); + TyTy::BaseType *expected_ty = nullptr; + bool ok = context->lookup_builtin ("usize", &expected_ty); + rust_assert (ok); + HIR::Expr *capacity_expr = nullptr; TyTy::BaseType *element_type = nullptr; TyTy::BaseType *capacity_type = nullptr; @@ -1072,9 +1077,6 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) auto capacity_expr_ty = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); context->insert_type (elems.get_num_copies_expr ().get_mappings (), expected_ty); @@ -1123,9 +1125,6 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) UNDEF_LOCATION, {}); // mark the type for this implicit node - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); context->insert_type (mapping, expected_ty); capacity_type = expected_ty; } @@ -1135,12 +1134,17 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) rust_assert (capacity_expr); rust_assert (capacity_type); auto ctx = Compile::Context::get (); - tree capacity + tree capacity_value = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, *capacity_expr); + HirId size_id = capacity_expr->get_mappings ().get_hirid (); + TyTy::ConstType *const_type + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", expected_ty, + capacity_value, {}, capacity_expr->get_locus (), + size_id, size_id); infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (), - capacity, TyTy::TyVar (element_type->get_ref ())); + const_type, TyTy::TyVar (element_type->get_ref ())); } // empty struct @@ -1798,7 +1802,7 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) TyTy::TyVar result_type = expr.has_return_type () ? TyTy::TyVar ( - TypeCheckType::Resolve (expr.get_return_type ())->get_ref ()) + TypeCheckType::Resolve (expr.get_return_type ())->get_ref ()) : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()); // resolve the block diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 76ff6903077d..c8544a1a9c27 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -70,7 +70,9 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (function.has_generics ()) { - resolve_generic_params (function.get_generic_params (), substitutions, + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions, true /*is_foreign*/, parent.get_abi ()); } @@ -200,7 +202,9 @@ TypeCheckImplItem::visit (HIR::Function &function) auto binder_pin = context->push_lifetime_binder (); if (function.has_generics ()) - resolve_generic_params (function.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : function.get_where_clause ().get_items ()) @@ -397,7 +401,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias) auto binder_pin = context->push_lifetime_binder (); if (alias.has_generics ()) - resolve_generic_params (alias.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::TypeAlias, alias.get_locus (), + alias.get_generic_params (), substitutions); TyTy::BaseType *actual_type = TypeCheckType::Resolve (alias.get_type_aliased ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index f104a1a56e81..3ba607bc5ab4 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -20,6 +20,7 @@ #include "optional.h" #include "rust-canonical-path.h" #include "rust-diagnostics.h" +#include "rust-hir-item.h" #include "rust-hir-type-check-enumitem.h" #include "rust-hir-type-check-implitem.h" #include "rust-hir-type-check-type.h" @@ -167,7 +168,9 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (struct_decl.has_generics ()) - resolve_generic_params (struct_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Struct, + struct_decl.get_locus (), + struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) @@ -238,7 +241,9 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (struct_decl.has_generics ()) - resolve_generic_params (struct_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Struct, + struct_decl.get_locus (), + struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) @@ -304,7 +309,8 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (enum_decl.has_generics ()) - resolve_generic_params (enum_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Enum, enum_decl.get_locus (), + enum_decl.get_generic_params (), substitutions); // Process #[repr(X)] attribute, if any const AST::AttrVec &attrs = enum_decl.get_outer_attrs (); @@ -364,7 +370,8 @@ TypeCheckItem::visit (HIR::Union &union_decl) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (union_decl.has_generics ()) - resolve_generic_params (union_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Union, union_decl.get_locus (), + union_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : union_decl.get_where_clause ().get_items ()) @@ -512,8 +519,9 @@ TypeCheckItem::visit (HIR::Function &function) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (function.has_generics ()) - resolve_generic_params (function.get_generic_params (), - substitutions); // TODO resolve constraints + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : function.get_where_clause ().get_items ()) @@ -700,7 +708,8 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, { std::vector<TyTy::SubstitutionParamMapping> substitutions; if (impl_block.has_generics ()) - resolve_generic_params (impl_block.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Impl, impl_block.get_locus (), + impl_block.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : impl_block.get_where_clause ().get_items ()) diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 2190faec7518..be926fcfddd3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -641,7 +641,8 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) { auto &array_ty_ty = static_cast<TyTy::ArrayType &> (*parent); parent_element_ty = array_ty_ty.get_element_type (); - tree cap = array_ty_ty.get_capacity (); + auto capacity = array_ty_ty.get_capacity (); + tree cap = capacity->get_value (); if (error_operand_p (cap)) { rust_error_at (parent->get_locus (), diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 21237f58868d..78037bdbd183 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -689,6 +689,7 @@ TypeCheckType::visit (HIR::ParenthesisedType &type) void TypeCheckType::visit (HIR::ArrayType &type) { + auto element_type = TypeCheckType::Resolve (type.get_element_type ()); auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ()); if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) return; @@ -698,21 +699,38 @@ TypeCheckType::visit (HIR::ArrayType &type) rust_assert (ok); context->insert_type (type.get_size_expr ().get_mappings (), expected_ty); - unify_site (type.get_size_expr ().get_mappings ().get_hirid (), - TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation (capacity_type, - type.get_size_expr ().get_locus ()), - type.get_size_expr ().get_locus ()); + TyTy::ConstType *const_type = nullptr; + if (capacity_type->get_kind () == TyTy::TypeKind::CONST) + { + const_type = static_cast<TyTy::ConstType *> (capacity_type); - TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); + unify_site (type.get_size_expr ().get_mappings ().get_hirid (), + TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (const_type->get_ty (), + type.get_size_expr ().get_locus ()), + type.get_size_expr ().get_locus ()); + } + else + { + HirId size_id = type.get_size_expr ().get_mappings ().get_hirid (); + unify_site (size_id, TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (capacity_type, + type.get_size_expr ().get_locus ()), + type.get_size_expr ().get_locus ()); + + auto ctx = Compile::Context::get (); + tree capacity_expr = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, capacity_type, type.get_size_expr ()); + + const_type = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + expected_ty, capacity_expr, {}, + type.get_size_expr ().get_locus (), + size_id, size_id); + } - auto ctx = Compile::Context::get (); - tree capacity - = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, - type.get_size_expr ()); translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), type.get_locus (), - capacity, TyTy::TyVar (base->get_ref ())); + const_type, TyTy::TyVar (element_type->get_ref ())); } void @@ -849,10 +867,9 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) if (param.has_type ()) TypeCheckType::Resolve (param.get_type ()); - resolved - = new TyTy::ParamType (param.get_type_representation ().as_string (), - param.get_locus (), - param.get_mappings ().get_hirid (), param, {}); + resolved = new TyTy::ParamType (param.get_type_representation ().as_string (), + param.get_locus (), + param.get_mappings ().get_hirid (), {}); if (resolve_trait_bounds) apply_trait_bounds (param, resolved); @@ -871,7 +888,7 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, HirId implicit_id = mappings.get_next_hir_id (); TyTy::ParamType *p = new TyTy::ParamType (param.get_type_representation ().as_string (), - param.get_locus (), implicit_id, param, + param.get_locus (), implicit_id, {} /*empty specified bounds*/); context->insert_implicit_type (implicit_id, p); diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 6097c4e5be87..aba4ab55c6c4 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -161,7 +161,9 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const HIR::TraitFunctionDecl &function = fn.get_decl (); if (function.has_generics ()) { - TypeCheckBase::ResolveGenericParams (function.get_generic_params (), + TypeCheckBase::ResolveGenericParams (HIR::Item::ItemKind::Function, + fn.get_locus (), + function.get_generic_params (), substitutions, false /*is_foreign*/, ABI::RUST); } diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index 01899d83435f..a47cde3b9664 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -18,18 +18,22 @@ #include "rust-tyty-subst.h" +#include "rust-hir-generic-param.h" #include "rust-system.h" #include "rust-tyty.h" #include "rust-hir-type-check.h" #include "rust-substitution-mapper.h" #include "rust-hir-type-check-type.h" +#include "rust-hir-type-check-expr.h" +#include "rust-compile-base.h" #include "rust-type-util.h" +#include "tree.h" namespace Rust { namespace TyTy { SubstitutionParamMapping::SubstitutionParamMapping (HIR::GenericParam &generic, - ParamType *param) + BaseGeneric *param) : generic (generic), param (param) {} @@ -87,9 +91,7 @@ SubstitutionParamMapping::needs_substitution () const Identifier SubstitutionParamMapping::get_type_representation () const { - rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE); - const auto &type_param = static_cast<const HIR::TypeParam &> (generic); - return type_param.get_type_representation (); + return param->get_symbol (); } location_t @@ -101,20 +103,35 @@ SubstitutionParamMapping::get_param_locus () const bool SubstitutionParamMapping::param_has_default_ty () const { - if (generic.get_kind () != HIR::GenericParam::GenericKind::TYPE) - return false; + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + const auto &type_param = static_cast<const HIR::TypeParam &> (generic); + return type_param.has_type (); + } - const auto &type_param = static_cast<const HIR::TypeParam &> (generic); - return type_param.has_type (); + rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST); + const auto &const_param + = static_cast<const HIR::ConstGenericParam &> (generic); + return const_param.has_default_expression (); } BaseType * SubstitutionParamMapping::get_default_ty () const { - rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE); + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + const auto &type_param = static_cast<const HIR::TypeParam &> (generic); + TyVar var (type_param.get_type_mappings ().get_hirid ()); + return var.get_tyty (); + } - const auto &type_param = static_cast<const HIR::TypeParam &> (generic); - TyVar var (type_param.get_type_mappings ().get_hirid ()); + rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST); + const auto &const_param + = static_cast<const HIR::ConstGenericParam &> (generic); + rust_assert (const_param.has_default_expression ()); + + const auto &expr = const_param.get_default_expression (); + TyVar var (expr.get_mappings ().get_hirid ()); return var.get_tyty (); } @@ -149,13 +166,15 @@ SubstitutionParamMapping::fill_param_ty ( // delete param; param = static_cast<ParamType *> (type.clone ()); } - else + else if (param->get_kind () == TypeKind::PARAM) { + auto &p = *static_cast<TyTy::ParamType *> (param); + // check the substitution is compatible with bounds rust_debug_loc (locus, "fill_param_ty bounds_compatible: param %s type %s", param->get_name ().c_str (), type.get_name ().c_str ()); - if (needs_bounds_check && !param->is_implicit_self_trait ()) + if (needs_bounds_check && !p.is_implicit_self_trait ()) { if (!param->bounds_compatible (type, locus, true)) return false; @@ -166,7 +185,7 @@ SubstitutionParamMapping::fill_param_ty ( bound.handle_substitions (subst_mappings); param->set_ty_ref (type.get_ref ()); - subst_mappings.on_param_subst (*param, arg); + subst_mappings.on_param_subst (p, arg); } return true; @@ -704,7 +723,9 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } - if (args.get_type_args ().size () + offs < min_required_substitutions ()) + size_t total_arguments + = args.get_type_args ().size () + args.get_const_args ().size () + offs; + if (total_arguments < min_required_substitutions ()) { rich_location r (line_table, args.get_locus ()); if (!substitutions.empty ()) @@ -747,12 +768,79 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } } + else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST) + { + if (!resolved->is<ConstType> ()) + { + rich_location r (line_table, arg->get_locus ()); + r.add_fixit_remove (arg->get_locus ()); + rust_error_at (r, ErrorCode::E0747, + "type provided when a constant was expected"); + return SubstitutionArgumentMappings::error (); + } + } SubstitutionArg subst_arg (¶m_mapping, resolved); offs++; mappings.push_back (std::move (subst_arg)); } + for (auto &arg : args.get_const_args ()) + { + auto &expr = *arg.get_expression ().get (); + BaseType *expr_type = Resolver::TypeCheckExpr::Resolve (expr); + if (expr_type == nullptr || expr_type->is<ErrorType> ()) + return SubstitutionArgumentMappings::error (); + + // validate this param is really a const generic + const auto ¶m_mapping = substitutions.at (offs); + const auto &generic = param_mapping.get_generic_param (); + if (generic.get_kind () != HIR::GenericParam::GenericKind::CONST) + { + rich_location r (line_table, arg.get_locus ()); + r.add_fixit_remove (expr.get_locus ()); + rust_error_at (r, "invalid position for a const generic argument"); + return SubstitutionArgumentMappings::error (); + } + + // get the const generic specified type + const auto base_generic = param_mapping.get_param_ty (); + rust_assert (base_generic->is<ConstType> ()); + const auto const_param + = static_cast<const TyTy::ConstType *> (base_generic); + auto specified_type = const_param->get_ty (); + + // validate this const generic is of the correct type + auto coereced_type + = Resolver::coercion_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (specified_type), + TyTy::TyWithLocation (expr_type, + expr.get_locus ()), + arg.get_locus ()); + if (coereced_type->is<ErrorType> ()) + return SubstitutionArgumentMappings::error (); + + // const fold it + auto ctx = Compile::Context::get (); + tree folded + = Compile::HIRCompileBase::query_compile_const_expr (ctx, coereced_type, + expr); + + if (folded == error_mark_node) + return SubstitutionArgumentMappings::error (); + + // create const type + auto const_value + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + coereced_type, folded, {}, expr.get_locus (), + expr.get_mappings ().get_hirid (), + expr.get_mappings ().get_hirid (), {}); + + SubstitutionArg subst_arg (¶m_mapping, const_value); + offs++; + mappings.push_back (std::move (subst_arg)); + } + // we must need to fill out defaults size_t left_over = num_required_substitutions () - min_required_substitutions (); @@ -798,22 +886,42 @@ SubstitutionRef::infer_substitions (location_t locus) std::map<std::string, BaseType *> argument_mappings; for (auto &p : get_substs ()) { + rust_debug_loc (locus, "XXXXXXXXXXXXXXXXXXXXXX 1: [%s]", + p.need_substitution () ? "true" : "false"); + p.get_param_ty ()->debug (); + if (p.needs_substitution ()) { + const HIR::GenericParam &generic = p.get_generic_param (); const std::string &symbol = p.get_param_ty ()->get_symbol (); auto it = argument_mappings.find (symbol); bool have_mapping = it != argument_mappings.end (); + rust_debug_loc (locus, "XXXXXXXXXXXXXXX 2: [%s] [%s]", + have_mapping ? "true" : "false", symbol.c_str ()); + if (have_mapping) { args.push_back (SubstitutionArg (&p, it->second)); } - else + else if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) { TyVar infer_var = TyVar::get_implicit_infer_var (locus); args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); argument_mappings[symbol] = infer_var.get_tyty (); } + else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST) + { + const auto const_param = p.get_param_ty (); + rust_assert (const_param->is<TyTy::ConstType> ()); + const auto &const_type + = *static_cast<const TyTy::ConstType *> (const_param); + + TyVar infer_var + = TyVar::get_implicit_const_infer_var (const_type, locus); + args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); + argument_mappings[symbol] = infer_var.get_tyty (); + } } else { diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index 0ac3ea73807d..69ef09896972 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -46,7 +46,7 @@ class SubstitutionArgumentMappings; class SubstitutionParamMapping { public: - SubstitutionParamMapping (HIR::GenericParam &generic, ParamType *param); + SubstitutionParamMapping (HIR::GenericParam &generic, BaseGeneric *param); SubstitutionParamMapping (const SubstitutionParamMapping &other); @@ -81,7 +81,7 @@ public: private: HIR::GenericParam &generic; - ParamType *param; + BaseGeneric *param; }; /** diff --git a/gcc/rust/typecheck/rust-tyty-util.cc b/gcc/rust/typecheck/rust-tyty-util.cc index ff210ce69e67..4bc17231bf12 100644 --- a/gcc/rust/typecheck/rust-tyty-util.cc +++ b/gcc/rust/typecheck/rust-tyty-util.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check.h" +#include "rust-mapping-common.h" +#include "rust-system.h" #include "rust-tyty.h" namespace Rust { @@ -47,14 +49,30 @@ TyVar::get_implicit_infer_var (location_t locus) auto &mappings = Analysis::Mappings::get (); auto context = Resolver::TypeCheckContext::get (); - InferType *infer = new InferType (mappings.get_next_hir_id (), - InferType::InferTypeKind::GENERAL, - InferType::TypeHint::Default (), locus); - context->insert_type (Analysis::NodeMapping (mappings.get_current_crate (), - UNKNOWN_NODEID, - infer->get_ref (), - UNKNOWN_LOCAL_DEFID), - infer); + HirId next = mappings.get_next_hir_id (); + auto infer = new InferType (next, InferType::InferTypeKind::GENERAL, + InferType::TypeHint::Default (), locus); + + context->insert_implicit_type (infer->get_ref (), infer); + mappings.insert_location (infer->get_ref (), locus); + + return TyVar (infer->get_ref ()); +} + +TyVar +TyVar::get_implicit_const_infer_var (const ConstType &const_type, + location_t locus) +{ + auto &mappings = Analysis::Mappings::get (); + auto context = Resolver::TypeCheckContext::get (); + + HirId next = mappings.get_next_hir_id (); + auto infer + = new ConstType (ConstType::ConstKind::Infer, const_type.get_symbol (), + const_type.get_ty (), error_mark_node, + const_type.get_specified_bounds (), locus, next, next, {}); + + context->insert_implicit_type (infer->get_ref (), infer); mappings.insert_location (infer->get_ref (), locus); return TyVar (infer->get_ref ()); diff --git a/gcc/rust/typecheck/rust-tyty-util.h b/gcc/rust/typecheck/rust-tyty-util.h index cbb3e8e65a10..1c8fd7237911 100644 --- a/gcc/rust/typecheck/rust-tyty-util.h +++ b/gcc/rust/typecheck/rust-tyty-util.h @@ -25,6 +25,7 @@ namespace Rust { namespace TyTy { class BaseType; +class ConstType; // this is a placeholder for types that can change like inference variables class TyVar @@ -42,6 +43,9 @@ public: static TyVar get_implicit_infer_var (location_t locus); + static TyVar get_implicit_const_infer_var (const TyTy::ConstType &const_type, + location_t locus); + static TyVar subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst); diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 260926931f00..a87efb4e3815 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -19,6 +19,7 @@ #include "rust-tyty.h" #include "optional.h" +#include "rust-tyty-subst.h" #include "rust-tyty-visitor.h" #include "rust-hir-map.h" #include "rust-location.h" @@ -31,10 +32,12 @@ #include "rust-type-util.h" #include "rust-hir-type-bounds.h" #include "print-tree.h" +#include "tree-pretty-print.h" #include "options.h" #include "rust-system.h" #include "tree.h" +#include <string> namespace Rust { namespace TyTy { @@ -829,7 +832,8 @@ BaseType::is_concrete () const } else if (auto arr = x->try_as<const ArrayType> ()) { - return arr->get_element_type ()->is_concrete (); + return arr->get_element_type ()->is_concrete () + && arr->get_capacity ()->is_concrete (); } else if (auto slice = x->try_as<const SliceType> ()) { @@ -858,6 +862,10 @@ BaseType::is_concrete () const return false; return closure->get_result_type ().is_concrete (); } + else if (auto const_type = x->try_as<const ConstType> ()) + { + return const_type->get_value () != error_mark_node; + } else if (x->is<InferType> () || x->is<BoolType> () || x->is<CharType> () || x->is<IntType> () || x->is<UintType> () || x->is<FloatType> () || x->is<USizeType> () || x->is<ISizeType> () || x->is<NeverType> () @@ -2491,16 +2499,8 @@ ArrayType::accept_vis (TyConstVisitor &vis) const std::string ArrayType::as_string () const { - std::string capacity_str = "<error>"; - if (!error_operand_p (capacity)) - { - unsigned HOST_WIDE_INT length = wi::to_wide (capacity).to_uhwi (); - - char buf[64]; - snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, length); - capacity_str = std::string (buf); - } - return "[" + get_element_type ()->as_string () + "; " + capacity_str + "]"; + return "[" + get_element_type ()->as_string () + "; " + capacity->as_string () + + "]"; } bool @@ -2556,6 +2556,13 @@ ArrayType::handle_substitions (SubstitutionArgumentMappings &mappings) BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); ref->element_type = TyVar::subst_covariant_var (base, concrete); + // handle capacity type + auto cap = ref->get_capacity (); + BaseType *concrete_cap + = Resolver::SubstMapperInternal::Resolve (cap, mappings); + rust_assert (concrete_cap->get_kind () == TyTy::TypeKind::CONST); + ref->capacity = static_cast<TyTy::ConstType *> (concrete_cap); + return ref; } @@ -3412,33 +3419,26 @@ PointerType::handle_substitions (SubstitutionArgumentMappings &mappings) // PARAM Type ParamType::ParamType (std::string symbol, location_t locus, HirId ref, - HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs) : BaseGeneric (ref, ref, KIND, {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), locus}, specified_bounds, refs), - is_trait_self (false), symbol (symbol), param (param) + is_trait_self (false), symbol (symbol) {} ParamType::ParamType (bool is_trait_self, std::string symbol, location_t locus, - HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + HirId ref, HirId ty_ref, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs) : BaseGeneric (ref, ty_ref, KIND, {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), locus}, specified_bounds, refs), - is_trait_self (is_trait_self), symbol (symbol), param (param) + is_trait_self (is_trait_self), symbol (symbol) {} -HIR::GenericParam & -ParamType::get_generic_param () -{ - return param; -} - bool ParamType::can_resolve () const { @@ -3489,7 +3489,7 @@ BaseType * ParamType::clone () const { return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (), - get_ty_ref (), param, get_specified_bounds (), + get_ty_ref (), get_specified_bounds (), get_combined_refs ()); } @@ -3592,12 +3592,14 @@ ConstType::ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, tree value, std::vector<TypeBoundPredicate> specified_bounds, location_t locus, HirId ref, HirId ty_ref, - HIR::GenericParam ¶m, std::set<HirId> refs) + std::set<HirId> refs) : BaseGeneric (ref, ty_ref, KIND, - {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, + symbol.empty () ? "<n/a>" + : symbol), locus}, specified_bounds, refs), - const_kind (kind), ty (ty), value (value), symbol (symbol), param (param) + const_kind (kind), ty (ty), value (value), symbol (symbol) {} void @@ -3612,6 +3614,13 @@ ConstType::accept_vis (TyConstVisitor &vis) const vis.visit (*this); } +void +ConstType::set_value (tree v) +{ + value = v; + const_kind = ConstType::ConstKind::Value; +} + std::string ConstType::as_string () const { @@ -3629,7 +3638,7 @@ BaseType * ConstType::clone () const { return new ConstType (const_kind, symbol, ty, value, get_specified_bounds (), - ident.locus, ref, ty_ref, param, get_combined_refs ()); + ident.locus, ref, ty_ref, get_combined_refs ()); } std::string @@ -3638,12 +3647,6 @@ ConstType::get_symbol () const return symbol; } -HIR::GenericParam & -ConstType::get_generic_param () -{ - return param; -} - bool ConstType::can_resolve () const { @@ -3657,10 +3660,48 @@ ConstType::resolve () const return nullptr; } +static std::string +generate_tree_str (tree value) +{ + char *buf = nullptr; + size_t size = 0; + + FILE *stream = open_memstream (&buf, &size); + if (!stream) + return "<error>"; + + print_generic_stmt (stream, value, TDF_NONE); + fclose (stream); + + std::string result = (buf ? std::string (buf, size) : "<error>"); + free (buf); + + if (!result.empty () && result.back () == '\n') + result.pop_back (); + + return result; +} + std::string ConstType::get_name () const { - return "CONST_TYPE"; + if (value == error_mark_node) + { + switch (get_const_kind ()) + { + case Rust::TyTy::ConstType::Decl: + return "ConstType:<" + get_ty ()->get_name () + " " + get_symbol () + + ">"; + + case Rust::TyTy::ConstType::Infer: + return "ConstType:<" + get_ty ()->get_name () + " ?" + ">"; + + default: + return "ConstType:<" + get_ty ()->get_name () + " - <error>" + ">"; + } + } + + return generate_tree_str (value); } bool @@ -3679,8 +3720,16 @@ ConstType::is_equal (const BaseType &other) const ConstType * ConstType::handle_substitions (SubstitutionArgumentMappings &mappings) { - rust_unreachable (); - return nullptr; + SubstitutionArg arg = SubstitutionArg::error (); + bool found = mappings.get_argument_for_symbol (this, &arg); + if (found && !arg.is_error ()) + { + TyTy::BaseType *subst = arg.get_tyty (); + rust_assert (subst->is<TyTy::ConstType> ()); + return static_cast<TyTy::ConstType *> (subst); + } + + return this; } // OpaqueType diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 7fd5c4695e65..585062b0cb79 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -19,6 +19,7 @@ #ifndef RUST_TYTY #define RUST_TYTY +#include "optional.h" #include "rust-hir-map.h" #include "rust-common.h" #include "rust-identifier.h" @@ -371,8 +372,6 @@ class BaseGeneric : public BaseType public: virtual std::string get_symbol () const = 0; - virtual HIR::GenericParam &get_generic_param () = 0; - virtual bool can_resolve () const = 0; virtual BaseType *resolve () const = 0; @@ -391,12 +390,11 @@ public: static constexpr auto KIND = TypeKind::PARAM; ParamType (std::string symbol, location_t locus, HirId ref, - HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()); ParamType (bool is_trait_self, std::string symbol, location_t locus, - HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + HirId ref, HirId ty_ref, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()); @@ -411,8 +409,6 @@ public: std::string get_symbol () const override final; - HIR::GenericParam &get_generic_param () override final; - bool can_resolve () const override final; BaseType *resolve () const override final; @@ -429,7 +425,6 @@ public: private: bool is_trait_self; std::string symbol; - HIR::GenericParam ¶m; }; class ConstType : public BaseGeneric @@ -447,7 +442,7 @@ public: ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, tree value, std::vector<TypeBoundPredicate> specified_bounds, location_t locus, - HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; @@ -457,6 +452,8 @@ public: TyTy::BaseType *get_ty () const { return ty; } tree get_value () const { return value; } + void set_value (tree value); + std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; @@ -465,8 +462,6 @@ public: std::string get_symbol () const override final; - HIR::GenericParam &get_generic_param () override final; - bool can_resolve () const override final; BaseType *resolve () const override final; @@ -482,7 +477,6 @@ private: TyTy::BaseType *ty; tree value; std::string symbol; - HIR::GenericParam ¶m; }; class OpaqueType : public BaseType @@ -1231,14 +1225,14 @@ class ArrayType : public BaseType public: static constexpr auto KIND = TypeKind::ARRAY; - ArrayType (HirId ref, location_t locus, tree capacity, TyVar base, + ArrayType (HirId ref, location_t locus, ConstType *capacity, TyVar base, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), element_type (base), capacity (capacity) {} - ArrayType (HirId ref, HirId ty_ref, location_t locus, tree capacity, + ArrayType (HirId ref, HirId ty_ref, location_t locus, ConstType *capacity, TyVar base, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ty_ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), @@ -1261,13 +1255,13 @@ public: BaseType *clone () const final override; - tree get_capacity () const { return capacity; } + ConstType *get_capacity () const { return capacity; } ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; - tree capacity; + ConstType *capacity; }; class SliceType : public BaseType diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 7780ae63f1ce..30ead5b4e0e9 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-unify.h" +#include "fold-const.h" #include "rust-tyty.h" #include "tree.h" @@ -839,20 +840,21 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) if (element_unify->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); - // TODO infer capacity? - tree lcap = ltype->get_capacity (); - tree rcap = type.get_capacity (); - if (error_operand_p (lcap) || error_operand_p (rcap)) - return new TyTy::ErrorType (0); + bool save_emit_error = emit_error; + emit_error = false; + TyTy::BaseType *capacity_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_capacity ()), + TyTy::TyWithLocation (type.get_capacity ())); + emit_error = save_emit_error; - auto lc = wi::to_wide (lcap).to_uhwi (); - auto rc = wi::to_wide (rcap).to_uhwi (); - if (lc != rc) + if (capacity_unify->get_kind () != TyTy::TypeKind::CONST) return new TyTy::ErrorType (0); + TyTy::ConstType *capacity_type_unify + = static_cast<TyTy::ConstType *> (capacity_unify); return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), type.get_ident ().locus, - type.get_capacity (), + capacity_type_unify, TyTy::TyVar (element_unify->get_ref ())); } break; @@ -1941,9 +1943,63 @@ UnifyRules::expect_const (TyTy::ConstType *ltype, TyTy::BaseType *rtype) if (rtype->get_kind () != TyTy::TypeKind::CONST) return new TyTy::ErrorType (0); - // TODO - // TyTy::ConstType &lhs = *ltype; - // TyTy::ConstType &rhs = *static_cast<TyTy::ConstType *> (rtype); + TyTy::ConstType &lhs = *ltype; + TyTy::ConstType &rhs = *static_cast<TyTy::ConstType *> (rtype); + + auto res = resolve_subtype (TyTy::TyWithLocation (lhs.get_ty ()), + TyTy::TyWithLocation (rhs.get_ty ())); + if (res->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + + tree lv = lhs.get_value (); + tree rv = rhs.get_value (); + + if (error_operand_p (lv) && error_operand_p (rv)) + { + // this is only allowed for some silly senarios like: + // gcc/testsuite/rust/compile/issue-const_generics_5.rs + if (lhs.get_const_kind () == rhs.get_const_kind ()) + { + return new TyTy::ConstType (lhs.get_const_kind (), lhs.get_symbol (), + res, error_mark_node, + lhs.get_specified_bounds (), + lhs.get_locus (), lhs.get_ref (), + lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } + + return new TyTy::ErrorType (0); + } + + bool equal = operand_equal_p (lv, rv, 0); + if (equal) + { + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + lhs.get_symbol (), res, lv, + lhs.get_specified_bounds (), lhs.get_locus (), + lhs.get_ref (), lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } + + if (lhs.get_const_kind () == TyTy::ConstType::Infer && !error_operand_p (rv)) + { + lhs.set_value (rv); + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + lhs.get_symbol (), res, rv, + lhs.get_specified_bounds (), lhs.get_locus (), + lhs.get_ref (), lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } + else if (rhs.get_const_kind () == TyTy::ConstType::Infer + && !error_operand_p (lv)) + { + rhs.set_value (lv); + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + rhs.get_symbol (), res, lv, + rhs.get_specified_bounds (), rhs.get_locus (), + rhs.get_ref (), rhs.get_ty_ref (), + rhs.get_combined_refs ()); + } return new TyTy::ErrorType (0); } diff --git a/gcc/testsuite/rust/compile/const_generics_10.rs b/gcc/testsuite/rust/compile/const_generics_10.rs new file mode 100644 index 000000000000..7e3bc86bd9fc --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_10.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +const M: usize = 4; + +struct Foo<T, const N: usize = 1> { + value: [T; N], +} + +fn main() { + let foo = Foo::<i32> { value: [15] }; + let foo = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; + let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, M> = Foo::<i32, 4> { + value: [15, 13, 11, 9], + }; + + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 3.. but got ...integer.; 2.. .E0308.} "" { target *-*-* } .-1 } + // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 3.. .E0308.} "" { target *-*-* } .-2 } + + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 4.. but got ...integer.; 2.. .E0308.} "" { target *-*-* } .-1 } + // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 4.. .E0308.} "" { target *-*-* } .-2 } + + let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 1.. but got ..T=i32; 2.. .E0308.} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_11.rs b/gcc/testsuite/rust/compile/const_generics_11.rs new file mode 100644 index 000000000000..de902ee0d06e --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_11.rs @@ -0,0 +1,14 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +struct Matrix<T, const ROWS: usize, const COLS: usize> { + data: [[T; COLS]; ROWS], +} + +fn main() { + let _: Matrix<u8, 2, 3> = Matrix { + data: [[1, 2, 3], [4, 5, 6]], + }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_12.rs b/gcc/testsuite/rust/compile/const_generics_12.rs new file mode 100644 index 000000000000..a17c52594b1f --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_12.rs @@ -0,0 +1,14 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +const BASE: usize = 2; + +struct Foo<T, const N: usize> { + data: [T; N], +} + +fn main() { + let _ = Foo::<u8, { BASE + 1 * 2 }> { data: [0; 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_13.rs b/gcc/testsuite/rust/compile/const_generics_13.rs new file mode 100644 index 000000000000..20dd0b906ce3 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_13.rs @@ -0,0 +1,11 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<T, const N: usize> { + value: [T; N], +} + +fn main() { + let foo: Foo<_, _>; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_14.rs b/gcc/testsuite/rust/compile/const_generics_14.rs new file mode 100644 index 000000000000..4d52efb16bb1 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_14.rs @@ -0,0 +1,13 @@ +#[lang = "sized"] +trait Sized {} + +type MyLen = usize; +struct Foo<T, const N: usize> { + data: [T; N], +} + +fn main() { + let _ = Foo::<u8, MyLen> { data: [1, 2, 3] }; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } + // { dg-error {expected an ADT type for constructor} "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_15.rs b/gcc/testsuite/rust/compile/const_generics_15.rs new file mode 100644 index 000000000000..a160abf59f1c --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_15.rs @@ -0,0 +1,16 @@ +#[lang = "sized"] +trait Sized {} + +enum Foo<const N: usize> { + A([u8; N]), +} + +union Bar<const N: usize> { + a: [i32; N], + b: [u8; N], +} + +fn main() { + let _ = Foo::<4>::A([1, 2, 3, 4]); + let _ = Bar::<4> { a: [0; 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_16.rs b/gcc/testsuite/rust/compile/const_generics_16.rs new file mode 100644 index 000000000000..060dbda79de6 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_16.rs @@ -0,0 +1,10 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<T = u8, const N: usize = 4> { + data: [T; N], // { dg-warning "field is never read: .data." } +} + +fn main() { + let _x = Foo { data: [1, 2, 3, 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs index d8b2ddfedaf0..3415f176b2f4 100644 --- a/gcc/testsuite/rust/compile/const_generics_3.rs +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -1,28 +1,21 @@ -// { dg-additional-options "-w -frust-compile-until=typecheck" } - #[lang = "sized"] trait Sized {} const M: usize = 4; struct Foo<T, const N: usize = 1> { - value: [T; N], + value: [T; N], // { dg-warning "field is never read: .value." } } fn main() { - let foo = Foo::<i32> { value: [15] }; - let foo = Foo::<i32, 2> { value: [15, 13] }; - let foo: Foo<i32, 2> = Foo { value: [15, 13] }; - let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; - let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; - let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; - let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; - let foo: Foo<i32, M> = Foo::<i32, 4> { + let _foo = Foo::<i32> { value: [15] }; + let _foo = Foo::<i32, 2> { value: [15, 13] }; + let _foo: Foo<i32, 2> = Foo { value: [15, 13] }; + let _foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; + let _foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; + let _foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let _foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let _foo: Foo<i32, M> = Foo::<i32, 4> { value: [15, 13, 11, 9], }; - - // FIXME: Add proper const typecheck errors here - let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] }; - let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] }; - let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] }; } diff --git a/gcc/testsuite/rust/compile/const_generics_5.rs b/gcc/testsuite/rust/compile/const_generics_5.rs index 685229eabd21..4d05569462bd 100644 --- a/gcc/testsuite/rust/compile/const_generics_5.rs +++ b/gcc/testsuite/rust/compile/const_generics_5.rs @@ -1,4 +1,3 @@ -// { dg-options "-w" } struct Foo<const N: usize = { 14 }>; const M: usize = 15; @@ -8,5 +7,6 @@ fn main() { let _: Foo<15> = Foo; let _: Foo<{ M }> = Foo; let _: Foo<M> = Foo; - // let _: Foo<N> = Foo; this causes an ICE we need to do const generics + let _: Foo<N> = Foo; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/const_generics_8.rs b/gcc/testsuite/rust/compile/const_generics_8.rs index bb34652b9a63..ce5e1b59bd71 100644 --- a/gcc/testsuite/rust/compile/const_generics_8.rs +++ b/gcc/testsuite/rust/compile/const_generics_8.rs @@ -9,12 +9,13 @@ type Bipboupe<const N: i32 = 15> = Bidule; trait Fooable<const N: i32 = 15> {} union Bidoulepe<const N: i32 = 15> { - // { dg-error "default values for const generic parameters are not allowed in .union. items" "" {target *-*-* } .-1 } int: i32, float: f32, } -fn const_default<const N: i32 = 15>() {} // { dg-error "default values for const generic parameters are not allowed in .function. items" } +fn const_default<const N: i32 = 15>() {} // { dg-error "default values for const generic parameters are not allowed here" } // Note - missing generic parameter - needs name resolution on const generics -impl<const N: i32 = 15> Bidule {} // { dg-error "default values for const generic parameters are not allowed in .impl. items" } +impl<const N: i32 = 15> Bidule {} +// { dg-error "default values for const generic parameters are not allowed here" "" {target *-*-* } .-1 } +// { dg-error "unconstrained type parameter" "" {target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/const_generics_9.rs b/gcc/testsuite/rust/compile/const_generics_9.rs new file mode 100644 index 000000000000..98e2d3ff0683 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_9.rs @@ -0,0 +1,13 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +struct ArrayWrapper<T, const N: usize> { + data: [T; N], +} + +pub fn test() -> [u8; 4] { + let a = ArrayWrapper { data: [1u8; 4] }; + a.data +}