diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-01-26 17:28:52 +0000 |
---|---|---|
committer | Philip Herron <herron.philip@googlemail.com> | 2021-01-27 10:42:43 +0000 |
commit | 244c2d2ea1a5a69ab6f7f50902512c1a7daa29c9 (patch) | |
tree | 6e7cd01cd95637ad9606570e5ee92d549bd85594 /gcc | |
parent | 8578c61be5061fab91fe679a15fd68ab5fad987c (diff) | |
download | gcc-244c2d2ea1a5a69ab6f7f50902512c1a7daa29c9.zip gcc-244c2d2ea1a5a69ab6f7f50902512c1a7daa29c9.tar.gz gcc-244c2d2ea1a5a69ab6f7f50902512c1a7daa29c9.tar.bz2 |
Support binding functions to LetStmts.
This supports basic function pointers in rust most of the code was already
there to infer this but this has now helped tidy it up and make it work.
Fixes #184
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-type.h | 4 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 28 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.cc | 32 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-type.h | 51 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-type.h | 34 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 22 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-toplevel.h | 3 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-type.h | 9 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 4 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 56 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-type.h | 28 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty-rules.h | 46 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.cc | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/compilable/function_reference1.rs | 8 | ||||
-rw-r--r-- | gcc/testsuite/rust.test/compilable/function_reference2.rs | 8 |
15 files changed, 292 insertions, 48 deletions
diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index 0dfeb07..a9e0f0f 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -816,6 +816,10 @@ public: rust_assert (param_type != nullptr); return param_type; } + + ParamKind get_param_kind () const { return param_kind; } + + Identifier get_name () const { return name; } }; /* A function pointer type - can be created via coercion from function items and diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 7c2f32d..81d7786 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -127,20 +127,28 @@ public: return; } - // this could be a constant reference - if (ctx->lookup_const_decl (ref, &translated)) - return; - - // must be an identifier + Bfunction *fn = nullptr; Bvariable *var = nullptr; - if (!ctx->lookup_var_decl (ref, &var)) + if (ctx->lookup_const_decl (ref, &translated)) { - rust_fatal_error (expr.get_locus (), - "failed to lookup compiled variable"); return; } - - translated = ctx->get_backend ()->var_expression (var, expr.get_locus ()); + else if (ctx->lookup_function_decl (ref, &fn)) + { + translated + = ctx->get_backend ()->function_code_expression (fn, + expr.get_locus ()); + } + else if (ctx->lookup_var_decl (ref, &var)) + { + translated + = ctx->get_backend ()->var_expression (var, expr.get_locus ()); + } + else + { + rust_fatal_error (expr.get_locus (), + "failed to lookup compiled reference"); + } } void visit (HIR::LiteralExpr &expr) diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 37285b7..818d5cb 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -28,23 +28,43 @@ void ResolvePathRef::visit (HIR::PathInExpression &expr) { // need to look up the reference for this identifier - NodeId ref_node_id; - if (!ctx->get_resolver ()->lookup_resolved_name ( + NodeId ref_node_id = UNKNOWN_NODEID; + if (ctx->get_resolver ()->lookup_resolved_name ( expr.get_mappings ().get_nodeid (), &ref_node_id)) { - return; + Resolver::Definition def; + if (!ctx->get_resolver ()->lookup_definition (ref_node_id, &def)) + { + rust_error_at (expr.get_locus (), + "unknown reference for resolved name"); + return; + } + ref_node_id = def.parent; } + // this can fail because it might be a Constructor for something + // in that case the caller should attempt ResolvePathType::Compile + if (ref_node_id == UNKNOWN_NODEID) + return; + HirId ref; if (!ctx->get_mappings ()->lookup_node_to_hir ( expr.get_mappings ().get_crate_num (), ref_node_id, &ref)) { - rust_error_at (expr.get_locus (), "reverse lookup failure"); + rust_error_at (expr.get_locus (), "reverse call path lookup failure"); return; } - // assumes paths are functions for now - Bfunction *fn; + // this might be a variable reference or a function reference + Bvariable *var = nullptr; + if (ctx->lookup_var_decl (ref, &var)) + { + resolved = ctx->get_backend ()->var_expression (var, expr.get_locus ()); + return; + } + + // must be a function call + Bfunction *fn = nullptr; if (!ctx->lookup_function_decl (ref, &fn)) { // this might fail because its a forward decl so we can attempt to diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 84d09bc..e78ae5a 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -42,6 +42,57 @@ public: return resolver.translated; } + void visit (AST::BareFunctionType &fntype) + { + bool is_variadic = false; + std::vector<HIR::LifetimeParam> lifetime_params; + HIR::FunctionQualifiers qualifiers ( + HIR::FunctionQualifiers::AsyncConstStatus::NONE, false); + + std::vector<HIR::MaybeNamedParam> named_params; + for (auto ¶m : fntype.get_function_params ()) + { + HIR::MaybeNamedParam::ParamKind kind; + switch (param.get_param_kind ()) + { + case AST::MaybeNamedParam::ParamKind::UNNAMED: + kind = HIR::MaybeNamedParam::ParamKind::UNNAMED; + break; + case AST::MaybeNamedParam::ParamKind::IDENTIFIER: + kind = HIR::MaybeNamedParam::ParamKind::IDENTIFIER; + break; + case AST::MaybeNamedParam::ParamKind::WILDCARD: + kind = HIR::MaybeNamedParam::ParamKind::WILDCARD; + break; + } + + HIR::Type *param_type + = ASTLoweringType::translate (param.get_type ().get ()); + + HIR::MaybeNamedParam p (param.get_name (), kind, + std::unique_ptr<HIR::Type> (param_type), + param.get_locus ()); + named_params.push_back (std::move (p)); + } + + HIR::Type *return_type = nullptr; + if (fntype.has_return_type ()) + { + return_type + = ASTLoweringType::translate (fntype.get_return_type ().get ()); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, fntype.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::BareFunctionType ( + std::move (mapping), std::move (lifetime_params), std::move (qualifiers), + std::move (named_params), is_variadic, + std::unique_ptr<HIR::Type> (return_type), fntype.get_locus ()); + } + void visit (AST::TupleType &tuple) { std::vector<std::unique_ptr<HIR::Type> > elems; diff --git a/gcc/rust/hir/tree/rust-hir-type.h b/gcc/rust/hir/tree/rust-hir-type.h index fc369c3..ebed119 100644 --- a/gcc/rust/hir/tree/rust-hir-type.h +++ b/gcc/rust/hir/tree/rust-hir-type.h @@ -791,6 +791,16 @@ public: } Location get_locus () const { return locus; } + + std::unique_ptr<Type> &get_type () + { + rust_assert (param_type != nullptr); + return param_type; + } + + ParamKind get_param_kind () const { return param_kind; } + + Identifier get_name () const { return name; } }; /* A function pointer type - can be created via coercion from function items and @@ -805,9 +815,7 @@ class BareFunctionType : public TypeNoBounds std::vector<MaybeNamedParam> params; bool is_variadic; - // bool has_return_type; - // BareFunctionReturnType return_type; - std::unique_ptr<TypeNoBounds> return_type; // inlined version + std::unique_ptr<Type> return_type; // inlined version Location locus; @@ -822,7 +830,7 @@ public: std::vector<LifetimeParam> lifetime_params, FunctionQualifiers qualifiers, std::vector<MaybeNamedParam> named_params, bool is_variadic, - std::unique_ptr<TypeNoBounds> type, Location locus) + std::unique_ptr<Type> type, Location locus) : TypeNoBounds (mappings), for_lifetimes (std::move (lifetime_params)), function_qualifiers (std::move (qualifiers)), params (std::move (named_params)), is_variadic (is_variadic), @@ -834,8 +842,7 @@ public: : TypeNoBounds (other.mappings), for_lifetimes (other.for_lifetimes), function_qualifiers (other.function_qualifiers), params (other.params), is_variadic (other.is_variadic), - return_type (other.return_type->clone_type_no_bounds ()), - locus (other.locus) + return_type (other.return_type->clone_type ()), locus (other.locus) {} // Overload assignment operator to deep copy @@ -846,7 +853,7 @@ public: function_qualifiers = other.function_qualifiers; params = other.params; is_variadic = other.is_variadic; - return_type = other.return_type->clone_type_no_bounds (); + return_type = other.return_type->clone_type (); locus = other.locus; return *this; @@ -862,6 +869,19 @@ public: void accept_vis (HIRVisitor &vis) override; + std::vector<MaybeNamedParam> &get_function_params () { return params; } + const std::vector<MaybeNamedParam> &get_function_params () const + { + return params; + } + + // TODO: would a "vis_type" be better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 9366818..f62f17c 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -102,16 +102,26 @@ public: void visit (AST::IdentifierExpr &expr) { - if (!resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (resolver->get_name_scope ().lookup (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)) + { + resolver->insert_resolved_type (expr.get_node_id (), resolved_node); + resolver->insert_new_definition (expr.get_node_id (), + Definition{expr.get_node_id (), + parent}); + } + else { rust_error_at (expr.get_locus (), "failed to find name: %s", expr.as_string ().c_str ()); - return; } - - resolver->insert_resolved_name (expr.get_node_id (), resolved_node); - resolver->insert_new_definition (expr.get_node_id (), - Definition{expr.get_node_id (), parent}); } void visit (AST::ArithmeticOrLogicalExpr &expr) diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 90f9cd6..c3f5e4c 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -75,6 +75,9 @@ public: resolver->get_name_scope ().insert (function.get_function_name (), function.get_node_id (), function.get_locus ()); + resolver->insert_new_definition (function.get_node_id (), + Definition{function.get_node_id (), + function.get_node_id ()}); // if this does not get a reference it will be determined to be unused // lets give it a fake reference to itself diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 20fb0b6..b303ee9 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -34,6 +34,15 @@ public: type->accept_vis (resolver); }; + void visit (AST::BareFunctionType &fntype) + { + for (auto ¶m : fntype.get_function_params ()) + ResolveType::go (param.get_type ().get (), fntype.get_node_id ()); + + if (fntype.has_return_type ()) + ResolveType::go (fntype.get_return_type ().get (), fntype.get_node_id ()); + } + void visit (AST::TupleType &tuple) { if (tuple.is_unit_type ()) diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 281049d..afc238b 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -550,8 +550,8 @@ Session::parse_file (const char *filename) type_resolution (hir); // FIXME this needs an option of itself - // auto buf = Resolver::TypeResolverDump::go (hir); - // fprintf (stderr, "%s\n", buf.c_str ()); + auto buf = Resolver::TypeResolverDump::go (hir); + fprintf (stderr, "%s\n", buf.c_str ()); if (saw_errors ()) return; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 17f1611..78f0d0d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -157,17 +157,32 @@ public: auto fn = expr.get_fnexpr (); auto fn_node_id = fn->get_mappings ().get_nodeid (); - // CallExpr might be a function but it might also be a TupleStruct - NodeId ref_node_id; - if (!resolver->lookup_resolved_name (fn_node_id, &ref_node_id)) + // then lookup the reference_node_id + NodeId ref_node_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (fn_node_id, &ref_node_id)) { - if (!resolver->lookup_resolved_type (fn_node_id, &ref_node_id)) + Definition def; + if (!resolver->lookup_definition (ref_node_id, &def)) { rust_error_at (expr.get_locus (), - "Failed to lookup reference for node: %s", - expr.as_string ().c_str ()); + "unknown reference for resolved name"); return; } + ref_node_id = def.parent; + } + else if (!resolver->lookup_resolved_type (fn_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; } // node back to HIR @@ -258,28 +273,39 @@ public: 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)) + 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; + } + 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 reference for node: %s", + "Failed to lookup type reference for node: %s", expr.as_string ().c_str ()); return; } - // 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)) + if (ref_node_id == UNKNOWN_NODEID) { - rust_error_at (expr.get_locus (), "unknown reference"); + rust_error_at (expr.get_locus (), "unresolved 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 (), - def.parent, &ref)) + ref_node_id, &ref)) { rust_error_at (expr.get_locus (), "reverse lookup failure"); return; diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index e5d3898..2894899 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -79,6 +79,34 @@ public: return resolver.translated; } + void visit (HIR::BareFunctionType &fntype) + { + TyTy::TyBase *return_type + = fntype.has_return_type () + ? TypeCheckType::Resolve (fntype.get_return_type ().get ()) + : new TyTy::UnitType (fntype.get_mappings ().get_hirid ()); + + std::vector<std::pair<HIR::Pattern *, TyTy::TyBase *> > params; + for (auto ¶m : fntype.get_function_params ()) + { + std::unique_ptr<HIR::Pattern> to_bind; + + bool is_ref = false; + bool is_mut = false; + + HIR::Pattern *pattern + = new HIR::IdentifierPattern (param.get_name (), param.get_locus (), + is_ref, is_mut, std::move (to_bind)); + + TyTy::TyBase *ptype = TypeCheckType::Resolve (param.get_type ().get ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::TyBase *> (pattern, ptype)); + } + + translated = new TyTy::FnType (fntype.get_mappings ().get_hirid (), + std::move (params), return_type); + } + void visit (HIR::TupleType &tuple) { if (tuple.is_unit_type ()) diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index e17cec7..be58805 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -410,6 +410,52 @@ class FnRules : public BaseRules public: FnRules (FnType *base) : BaseRules (base), base (base) {} + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + resolved->set_ref (type.get_ref ()); + } + + void visit (FnType &type) override + { + if (base->num_params () != type.num_params ()) + { + BaseRules::visit (type); + return; + } + + // FIXME add an abstract method for is_equal on TyBase + 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 combined_param = a->combine (b); + if (combined_param == nullptr) + { + BaseRules::visit (type); + return; + } + } + + auto combined_return + = base->get_return_type ()->combine (type.get_return_type ()); + if (combined_return == nullptr) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + resolved->set_ref (type.get_ref ()); + } + private: FnType *base; }; diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 249e876..d506415 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -147,11 +147,14 @@ ADTType::accept_vis (TyVisitor &vis) std::string ADTType::as_string () const { + if (num_fields () == 0) + return identifier; + std::string fields_buffer; for (auto &field : fields) - fields_buffer += field->as_string () + "\n"; + fields_buffer += field->as_string () + ", "; - return identifier + "{\n" + fields_buffer + "\n}"; + return identifier + "{" + fields_buffer + "}"; } TyBase * diff --git a/gcc/testsuite/rust.test/compilable/function_reference1.rs b/gcc/testsuite/rust.test/compilable/function_reference1.rs new file mode 100644 index 0000000..604bad0 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/function_reference1.rs @@ -0,0 +1,8 @@ +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a = test; + let b = a(1); +} diff --git a/gcc/testsuite/rust.test/compilable/function_reference2.rs b/gcc/testsuite/rust.test/compilable/function_reference2.rs new file mode 100644 index 0000000..0b963b2 --- /dev/null +++ b/gcc/testsuite/rust.test/compilable/function_reference2.rs @@ -0,0 +1,8 @@ +fn test(a: i32) -> i32 { + a + 1 +} + +fn main() { + let a: fn(i32) -> i32 = test; + let b = a(1); +} |