diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-04-13 10:50:13 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 10:50:13 +0000 |
commit | 636ad7d95e0f2afa1544ba7deeadf3d52de18a82 (patch) | |
tree | fc50976ff47ed0e69ec2d483188e075f7066d2d2 /gcc/rust | |
parent | ca8744db3e56bfcf0cf3f0e2a0bf76450aef9438 (diff) | |
parent | 4ee35b6edb549be11571536bf78f8585a0282991 (diff) | |
download | gcc-636ad7d95e0f2afa1544ba7deeadf3d52de18a82.zip gcc-636ad7d95e0f2afa1544ba7deeadf3d52de18a82.tar.gz gcc-636ad7d95e0f2afa1544ba7deeadf3d52de18a82.tar.bz2 |
Merge #358
358: Canonical Paths for Name Resolution and handle TurboFish properly r=philberty a=philberty
Add Canonical paths to name resolution
In order to support name resolution and checks for duplicate definitions
of names we need canonical paths for all DefId items such as inherent impl
items and normal items. Consider:
```rust
struct Foo<T>(T);
impl Foo<f32> {
fn name()...
}
impl Foo<i32> {
fn name()...
}
```
Each of the impl blocks have a name function but these are separate due to
the concrete impl of the Parameter type passed in.
The caveat here is that to call this Function name the programmer must be
explicit in which implentation they wish to call such as:
```rust
let a = Foo::<f32>::name();
```
This lets the Path probe lookup the appropriate impl block. The problem here
is that rust also allows for the compiler to infer the impl you wish such
as:
```rust
let a = Foo::name();
```
This should fail since there are multiple candidates possible for this
Path. Unless there might have only been one name function in which case
it would have worked.
This patch is also responsible to implement PathInExpression by iterating
each segment and applying generic arguments as we go.
Fixes #355 #335 #325 #353
Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc/rust')
27 files changed, 2161 insertions, 440 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index d0c752c..f98ebc6 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -526,7 +526,7 @@ public: void visit (HIR::PathInExpression &expr) override { - translated = ResolvePathRef::Compile (&expr, ctx); + translated = ResolvePathRef::Compile (expr, ctx); } void visit (HIR::LoopExpr &expr) override diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h index da1d97e..30486d0 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.h +++ b/gcc/rust/backend/rust-compile-resolve-path.h @@ -30,10 +30,10 @@ class ResolvePathRef : public HIRCompileBase using Rust::Compile::HIRCompileBase::visit; public: - static Bexpression *Compile (HIR::Expr *expr, Context *ctx) + static Bexpression *Compile (HIR::PathInExpression &expr, Context *ctx) { ResolvePathRef resolver (ctx); - expr->accept_vis (resolver); + expr.accept_vis (resolver); return resolver.resolved; } diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index edbc498..18ead3c 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -360,12 +360,14 @@ public: mappings->get_next_localdef_id (crate_num)); std::vector<std::unique_ptr<HIR::InherentImplItem> > impl_items; + std::vector<HirId> impl_item_ids; for (auto &impl_item : impl_block.get_impl_items ()) { HIR::InherentImplItem *lowered = ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ()); impl_items.push_back (std::unique_ptr<HIR::InherentImplItem> (lowered)); + impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ()); } translated @@ -381,6 +383,13 @@ public: translated); mappings->insert_location (crate_num, mapping.get_hirid (), impl_block.get_locus ()); + + for (auto &impl_item_id : impl_item_ids) + { + mappings->insert_impl_item_mapping (impl_item_id, + static_cast<HIR::InherentImpl *> ( + translated)); + } } private: diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 8dbde9c..d6f9fc0 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -255,6 +255,12 @@ public: } } + size_t get_num_segments () const { return segments.size (); } + + std::vector<PathExprSegment> &get_segments () { return segments; } + + PathExprSegment &get_root_seg () { return segments.at (0); } + PathExprSegment get_final_segment () const { return segments.back (); } }; diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 48cc18e..fbf05f2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -109,15 +109,16 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) { resolver->insert_resolved_name (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), Definition{expr.get_node_id (), parent}); } - else if (resolver->get_type_scope ().lookup (expr.as_string (), - &resolved_node)) + else if (resolver->get_type_scope ().lookup ( + CanonicalPath (expr.as_string ()), &resolved_node)) { resolver->insert_resolved_type (expr.get_node_id (), resolved_node); resolver->insert_new_definition (expr.get_node_id (), @@ -255,8 +256,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -281,8 +283,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); @@ -311,8 +313,9 @@ public: auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( - label_name, label_lifetime_node_id, label.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (label_name), label_lifetime_node_id, + label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -338,8 +341,8 @@ public: } NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_label_scope ().lookup (label.get_lifetime_name (), - &resolved_node)) + if (!resolver->get_label_scope ().lookup ( + CanonicalPath (label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h index d88b275f..46343c2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-implitem.h +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -31,25 +31,19 @@ class ResolveToplevelImplItem : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::InherentImplItem *item, AST::Type *base) + static void go (AST::InherentImplItem *item, const CanonicalPath &prefix) { - ResolveToplevelImplItem resolver (base); - if (resolver.base_path.is_empty ()) - { - rust_error_at (base->get_locus_slow (), - "failed to resolve simple path"); - return; - } + ResolveToplevelImplItem resolver (prefix); item->accept_vis (resolver); } void visit (AST::ConstantItem &constant) override { - std::string identifier - = base_path.as_string () + "::" + constant.get_identifier (); + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - identifier, constant.get_node_id (), constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -60,11 +54,11 @@ public: void visit (AST::Function &function) override { - std::string identifier - = base_path.as_string () + "::" + function.get_function_name (); + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - identifier, function.get_node_id (), function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -75,11 +69,11 @@ public: void visit (AST::Method &method) override { - std::string identifier - = base_path.as_string () + "::" + method.get_method_name (); + auto path + = prefix.append (ResolveMethodItemToCanonicalPath::resolve (method)); resolver->get_name_scope ().insert ( - identifier, method.get_node_id (), method.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, method.get_node_id (), method.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (method.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -89,15 +83,13 @@ public: } private: - ResolveToplevelImplItem (AST::Type *base) - : ResolverBase (UNKNOWN_NODEID), base (base), - base_path (AST::SimplePath::create_empty ()) + ResolveToplevelImplItem (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) { - ResolveTypeToSimplePath::go (base, base_path, true); + rust_assert (!prefix.is_error ()); } - AST::Type *base; - AST::SimplePath base_path; + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 45d94db..9c19ce6 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -179,18 +179,21 @@ public: } } + bool canonicalize_type_with_generics = false; NodeId resolved_node = ResolveType::go (impl_block.get_type ().get (), - impl_block.get_node_id ()); + impl_block.get_node_id (), + canonicalize_type_with_generics); if (resolved_node == UNKNOWN_NODEID) return; + auto Self = CanonicalPath::get_big_self (); resolver->get_type_scope ().insert ( - "Self", resolved_node, impl_block.get_type ()->get_locus_slow ()); + Self, resolved_node, impl_block.get_type ()->get_locus_slow ()); for (auto &impl_item : impl_block.get_impl_items ()) impl_item->accept_vis (*this); - resolver->get_type_scope ().peek ()->clear_name ("Self", resolved_node); + resolver->get_type_scope ().peek ()->clear_name (Self, resolved_node); resolver->get_type_scope ().pop (); } diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 147bf72..0734908 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -33,7 +33,6 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { ResolvePattern resolver (parent); - pattern->accept_vis (resolver); if (resolver.resolved_node == UNKNOWN_NODEID) { @@ -42,12 +41,10 @@ public: } }; - ~ResolvePattern () {} - void visit (AST::IdentifierPattern &pattern) override { - if (resolver->get_name_scope ().lookup (pattern.get_ident (), - &resolved_node)) + if (resolver->get_name_scope ().lookup ( + CanonicalPath (pattern.get_ident ()), &resolved_node)) { resolver->insert_resolved_name (pattern.get_node_id (), resolved_node); resolver->insert_new_definition (pattern.get_node_id (), @@ -68,23 +65,14 @@ public: static void go (AST::Pattern *pattern, NodeId parent) { PatternDeclaration resolver (parent); - pattern->accept_vis (resolver); - if (resolver.resolved_node != UNKNOWN_NODEID) - { - // print both locations?! - rust_error_at (resolver.locus, "duplicate pattern %s", - pattern->as_string ().c_str ()); - } }; - ~PatternDeclaration () {} - void visit (AST::IdentifierPattern &pattern) override { // if we have a duplicate id this then allows for shadowing correctly // as new refs to this decl will match back here so it is ok to overwrite - resolver->get_name_scope ().insert (pattern.get_ident (), + resolver->get_name_scope ().insert (CanonicalPath (pattern.get_ident ()), pattern.get_node_id (), pattern.get_locus ()); resolver->insert_new_definition (pattern.get_node_id (), diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index afc0068..2550c39 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -32,17 +32,19 @@ class ResolveTopLevel : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::Item *item) + static void go (AST::Item *item, + const CanonicalPath &prefix = CanonicalPath::create_empty ()) { - ResolveTopLevel resolver; + ResolveTopLevel resolver (prefix); item->accept_vis (resolver); }; void visit (AST::TypeAlias &alias) override { resolver->get_type_scope ().insert ( - alias.get_new_type_name (), alias.get_node_id (), alias.get_locus (), - false, [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (alias.get_new_type_name ()), alias.get_node_id (), + alias.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (alias.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -51,9 +53,9 @@ public: void visit (AST::TupleStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -62,9 +64,9 @@ public: void visit (AST::StructStruct &struct_decl) override { resolver->get_type_scope ().insert ( - struct_decl.get_identifier (), struct_decl.get_node_id (), + CanonicalPath (struct_decl.get_identifier ()), struct_decl.get_node_id (), struct_decl.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (struct_decl.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -73,8 +75,9 @@ public: void visit (AST::StaticItem &var) override { resolver->get_name_scope ().insert ( - var.get_identifier (), var.get_node_id (), var.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + CanonicalPath (var.get_identifier ()), var.get_node_id (), + var.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (var.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -86,10 +89,11 @@ public: void visit (AST::ConstantItem &constant) override { + auto path + = prefix.append (ResolveConstantItemToCanonicalPath::resolve (constant)); resolver->get_name_scope ().insert ( - constant.get_identifier (), constant.get_node_id (), - constant.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (constant.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -100,10 +104,11 @@ public: void visit (AST::Function &function) override { + auto path + = prefix.append (ResolveFunctionItemToCanonicalPath::resolve (function)); resolver->get_name_scope ().insert ( - function.get_function_name (), function.get_node_id (), - function.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (function.get_locus (), "redefined multiple times"); rust_error_at (locus, "was defined here"); }); @@ -122,13 +127,24 @@ public: void visit (AST::InherentImpl &impl_block) override { + bool canonicalize_type_args = !impl_block.has_generics (); + bool type_resolve_generic_args = false; + CanonicalPath impl_type + = ResolveTypeToCanonicalPath::resolve (*impl_block.get_type ().get (), + canonicalize_type_args, + type_resolve_generic_args); + CanonicalPath impl_prefix = prefix.append (impl_type); + for (auto &impl_item : impl_block.get_impl_items ()) - ResolveToplevelImplItem::go (impl_item.get (), - impl_block.get_type ().get ()); + ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); } private: - ResolveTopLevel () : ResolverBase (UNKNOWN_NODEID) {} + ResolveTopLevel (const CanonicalPath &prefix) + : ResolverBase (UNKNOWN_NODEID), prefix (prefix) + {} + + const CanonicalPath &prefix; }; } // namespace Resolver diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 9e7568e..35e04a8 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -25,73 +25,136 @@ namespace Rust { namespace Resolver { -class ResolveTypeToSimplePath : public ResolverBase +class ResolveConstantItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::ConstantItem &constant) + { + return CanonicalPath (constant.get_identifier ()); + } +}; + +class ResolveFunctionItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Function &function) + { + return CanonicalPath (function.get_function_name ()); + } +}; + +class ResolveMethodItemToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::Method &method) + { + return CanonicalPath (method.get_method_name ()); + } +}; + +class ResolveTypeToCanonicalPath : public ResolverBase { using Rust::Resolver::ResolverBase::visit; public: - static bool go (AST::Type *type, AST::SimplePath &simple_path_result, - bool path_only = false) + static CanonicalPath resolve (AST::Type &type, + bool include_generic_args = true, + bool type_resolve_generic_args = true) { - ResolveTypeToSimplePath resolver (simple_path_result, path_only); - type->accept_vis (resolver); - return !resolver.type_seg_failed_flag; + ResolveTypeToCanonicalPath resolver (include_generic_args, + type_resolve_generic_args); + type.accept_vis (resolver); + return resolver.result; } void visit (AST::TypePath &path) override { - segs.reserve (path.get_num_segments ()); for (auto &seg : path.get_segments ()) { seg->accept_vis (*this); - if (type_seg_failed_flag) + if (failure_flag) return; } - - if (segs.empty ()) - { - rust_error_at (path.get_locus (), "failed to resolve path: %s", - path.as_string ().c_str ()); - return; - } - - bool has_opening_scope_res = false; - result = AST::SimplePath (std::move (segs), has_opening_scope_res, - path.get_locus ()); } void visit (AST::TypePathSegmentGeneric &seg) override; void visit (AST::TypePathSegment &seg) override; + static CanonicalPath canonicalize_generic_args (AST::GenericArgs &args); + + static bool type_resolve_generic_args (AST::GenericArgs &args); + private: - ResolveTypeToSimplePath (AST::SimplePath &simple_path_result, bool path_only) - : ResolverBase (UNKNOWN_NODEID), type_seg_failed_flag (false), - result (simple_path_result), path_only_flag (path_only) + ResolveTypeToCanonicalPath (bool include_generic_args, + bool type_resolve_generic_args) + : ResolverBase (UNKNOWN_NODEID), result (CanonicalPath::create_empty ()), + include_generic_args_flag (include_generic_args), + type_resolve_generic_args_flag (type_resolve_generic_args), + failure_flag (false) {} - bool type_seg_failed_flag; - std::vector<AST::SimplePathSegment> segs; - AST::SimplePath &result; - bool path_only_flag; + CanonicalPath result; + bool include_generic_args_flag; + bool type_resolve_generic_args_flag; + bool failure_flag; +}; + +class ResolvePathSegmentToCanonicalPath +{ +public: + static CanonicalPath resolve (AST::PathExprSegment &seg) + { + CanonicalPath path = CanonicalPath (seg.get_ident_segment ().as_string ()); + if (seg.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + seg.get_generic_args ()); + if (!ok) + { + rust_error_at (seg.get_locus (), + "failed to resolve all generic args"); + return CanonicalPath::create_empty (); + } + + path + = path.append (ResolveTypeToCanonicalPath::canonicalize_generic_args ( + seg.get_generic_args ())); + } + return path; + } }; -class ResolveTypePath +// FIXME: as part of imports and visibility we need to be able to keep a context +// for handling PathInExpressions segments as they can be local to a particular +// lexical scope requiring a context to be maintained for resolution +class ResolveRelativeTypePath { public: - static NodeId go (AST::TypePath &path, NodeId parent) + static NodeId go (AST::TypePath &path, NodeId parent, + const CanonicalPath &prefix, + bool canonicalize_type_with_generics) { - AST::SimplePath path_buffer = AST::SimplePath::create_empty (); - if (!ResolveTypeToSimplePath::go (&path, path_buffer)) - return UNKNOWN_NODEID; + CanonicalPath canonical_path + = ResolveTypeToCanonicalPath::resolve (path, + canonicalize_type_with_generics, + true); + if (canonical_path.is_error ()) + { + rust_error_at (path.get_locus (), "Failed to resolve canonical path"); + return UNKNOWN_NODEID; + } + + CanonicalPath lookup = canonical_path; + if (!prefix.is_error ()) + lookup = prefix.append (canonical_path); auto resolver = Resolver::get (); NodeId resolved_node = UNKNOWN_NODEID; - if (!resolver->get_type_scope ().lookup (path_buffer.as_string (), - &resolved_node)) + if (!resolver->get_type_scope ().lookup (canonical_path, &resolved_node)) { rust_error_at (path.get_locus_slow (), "failed to resolve TypePath: %s", - path_buffer.as_string ().c_str ()); + canonical_path.get ().c_str ()); return UNKNOWN_NODEID; } @@ -104,9 +167,10 @@ class ResolveType : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static NodeId go (AST::Type *type, NodeId parent) + static NodeId go (AST::Type *type, NodeId parent, + bool canonicalize_type_with_generics = false) { - ResolveType resolver (parent); + ResolveType resolver (parent, canonicalize_type_with_generics); type->accept_vis (resolver); if (!resolver.ok) rust_error_at (type->get_locus_slow (), "unresolved type"); @@ -139,7 +203,10 @@ public: void visit (AST::TypePath &path) override { - resolved_node = ResolveTypePath::go (path, parent); + resolved_node + = ResolveRelativeTypePath::go (path, parent, + CanonicalPath::create_empty (), + canonicalize_type_with_generics); ok = resolved_node != UNKNOWN_NODEID; if (ok) { @@ -160,12 +227,16 @@ public: type.get_type_referenced ()->accept_vis (*this); } - // nothing to do for inferred types void visit (AST::InferredType &type) override { ok = true; } private: - ResolveType (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveType (NodeId parent, bool canonicalize_type_with_generics) + : ResolverBase (parent), + canonicalize_type_with_generics (canonicalize_type_with_generics), + ok (false) + {} + bool canonicalize_type_with_generics; bool ok; }; @@ -190,9 +261,9 @@ public: // for now lets focus on handling the basics: like struct<T> { a:T, ....} resolver->get_type_scope ().insert ( - param.get_type_representation (), param.get_node_id (), + CanonicalPath (param.get_type_representation ()), param.get_node_id (), param.get_locus (), false, - [&] (std::string, NodeId, Location locus) -> void { + [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (param.get_locus (), "generic param redefined multiple times"); rust_error_at (locus, "was defined here"); @@ -200,7 +271,11 @@ public: } private: - ResolveGenericParam (NodeId parent) : ResolverBase (parent), ok (false) {} + ResolveGenericParam (NodeId parent) + : ResolverBase (parent), + + ok (false) + {} bool ok; }; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 4cc1a93..aac55e2 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -50,7 +50,8 @@ Resolver::Resolver () : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()), name_scope (Scope (mappings->get_current_crate ())), type_scope (Scope (mappings->get_current_crate ())), - label_scope (Scope (mappings->get_current_crate ())) + label_scope (Scope (mappings->get_current_crate ())), + global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID) { generate_builtins (); } @@ -116,9 +117,12 @@ Resolver::insert_builtin_types (Rib *r) { auto builtins = get_builtin_types (); for (auto &builtin : builtins) - r->insert_name (builtin->as_string (), builtin->get_node_id (), - Linemap::predeclared_location (), false, - [] (std::string, NodeId, Location) -> void {}); + { + CanonicalPath builtin_path (builtin->as_string ()); + r->insert_name (builtin_path, builtin->get_node_id (), + Linemap::predeclared_location (), false, + [] (const CanonicalPath &, NodeId, Location) -> void {}); + } } std::vector<AST::Type *> & @@ -374,41 +378,84 @@ ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field) // rust-ast-resolve-type.h -void -ResolveTypeToSimplePath::visit (AST::TypePathSegmentGeneric &seg) +CanonicalPath +ResolveTypeToCanonicalPath::canonicalize_generic_args (AST::GenericArgs &args) { - if (!path_only_flag) + std::string buf; + + size_t i = 0; + size_t total = args.get_type_args ().size (); + + for (auto &ty_arg : args.get_type_args ()) { - AST::GenericArgs &generics = seg.get_generic_args (); - for (auto > : generics.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); + buf += ty_arg->as_string (); + if ((i + 1) < total) + buf += ","; + + i++; } + return CanonicalPath ("<" + buf + ">"); +} + +bool +ResolveTypeToCanonicalPath::type_resolve_generic_args (AST::GenericArgs &args) +{ + for (auto > : args.get_type_args ()) + { + ResolveType::go (gt.get (), UNKNOWN_NODEID); + // FIXME error handling here for inference variable since they do not have + // a node to resolve to + // if (resolved == UNKNOWN_NODEID) return false; + } + return true; +} + +void +ResolveTypeToCanonicalPath::visit (AST::TypePathSegmentGeneric &seg) +{ if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + // ident seg + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); + + // generic args + if (seg.has_generic_args ()) + { + if (include_generic_args_flag) + result + = result.append (canonicalize_generic_args (seg.get_generic_args ())); + + if (type_resolve_generic_args_flag) + { + bool ok = type_resolve_generic_args (seg.get_generic_args ()); + failure_flag = !ok; + } + } } void -ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) +ResolveTypeToCanonicalPath::visit (AST::TypePathSegment &seg) { if (seg.is_error ()) { - type_seg_failed_flag = true; - rust_error_at (Location (), "segment has error: %s", + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", seg.as_string ().c_str ()); return; } - segs.push_back (AST::SimplePathSegment (seg.get_ident_segment ().as_string (), - seg.get_locus ())); + CanonicalPath ident_seg + = CanonicalPath (seg.get_ident_segment ().as_string ()); + result = result.append (ident_seg); } // rust-ast-resolve-expr.h @@ -416,38 +463,77 @@ ResolveTypeToSimplePath::visit (AST::TypePathSegment &seg) void ResolvePath::resolve_path (AST::PathInExpression *expr) { - // this needs extended similar to the TypePath to lookup each segment - // in turn then look its rib for the next segment and so forth until we - // resolve to a final NodeId generic args can be ignored - std::string path_buf; - for (auto &seg : expr->get_segments ()) + // resolve root segment first then apply segments in turn + AST::PathExprSegment &root_segment = expr->get_segments ().at (0); + AST::PathIdentSegment &root_ident_seg = root_segment.get_ident_segment (); + + bool segment_is_type = false; + CanonicalPath root_seg_path (root_ident_seg.as_string ()); + + // name scope first + if (resolver->get_name_scope ().lookup (root_seg_path, &resolved_node)) { - auto s = seg.get_ident_segment (); - if (s.is_error () && !seg.has_generic_args ()) + segment_is_type = false; + resolver->insert_resolved_name (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (root_seg_path, &resolved_node)) + { + segment_is_type = true; + resolver->insert_resolved_type (root_segment.get_node_id (), + resolved_node); + resolver->insert_new_definition (root_segment.get_node_id (), + Definition{expr->get_node_id (), + parent}); + } + else + { + rust_error_at (expr->get_locus (), + "unknown root segment in path %s lookup %s", + expr->as_string ().c_str (), + root_ident_seg.as_string ().c_str ()); + return; + } + + if (root_segment.has_generic_args ()) + { + bool ok = ResolveTypeToCanonicalPath::type_resolve_generic_args ( + root_segment.get_generic_args ()); + if (!ok) { - rust_error_at (expr->get_locus (), "malformed path"); + rust_error_at (root_segment.get_locus (), + "failed to resolve generic args"); return; } + } - if (seg.has_generic_args ()) - { - AST::GenericArgs &args = seg.get_generic_args (); - for (auto > : args.get_type_args ()) - ResolveType::go (gt.get (), UNKNOWN_NODEID); - } + if (expr->is_single_segment ()) + { + if (segment_is_type) + resolver->insert_resolved_type (expr->get_node_id (), resolved_node); + else + resolver->insert_resolved_name (expr->get_node_id (), resolved_node); - if (!s.is_error ()) - { - bool needs_sep = !path_buf.empty (); - if (needs_sep) - path_buf += "::"; + resolver->insert_new_definition (expr->get_node_id (), + Definition{expr->get_node_id (), + parent}); + return; + } - path_buf += s.as_string (); - } + // we can attempt to resolve this path fully + CanonicalPath path = root_seg_path; + for (size_t i = 1; i < expr->get_segments ().size (); i++) + { + AST::PathExprSegment &seg = expr->get_segments ().at (i); + auto s = ResolvePathSegmentToCanonicalPath::resolve (seg); + path = path.append (s); } - // name scope first - if (resolver->get_name_scope ().lookup (path_buf, &resolved_node)) + if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_name (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -455,7 +541,7 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) parent}); } // check the type scope - else if (resolver->get_type_scope ().lookup (path_buf, &resolved_node)) + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_type (expr->get_node_id (), resolved_node); resolver->insert_new_definition (expr->get_node_id (), @@ -464,8 +550,42 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } else { - rust_error_at (expr->get_locus (), "unknown path %s lookup %s", - expr->as_string ().c_str (), path_buf.c_str ()); + // attempt to fully resolve the path which is allowed to fail given the + // following scenario + // + // https://github.com/Rust-GCC/gccrs/issues/355 Paths are + // resolved fully here, there are limitations though imagine: + // + // struct Foo<A> (A); + // + // impl Foo<isize> { + // fn test() -> ... + // + // impl Foo<f32> { + // fn test() -> ... + // + // fn main() { + // let a:i32 = Foo::test(); + // + // there are multiple paths that test can resolve to Foo::<?>::test here + // so we cannot resolve this case + // + // canonical names: + // + // struct Foo<A> -> Foo + // impl Foo<isize>::fn test -> Foo::isize::test + // impl Foo<f32>::fn test -> Foo::f32::test + // + // Since there is the case we have the following paths for test: + // + // Foo::isize::test + // Foo::f32::test + // vs + // Foo::test + // + // but the lookup was simply Foo::test we must rely on type resolution to + // figure this type out in a similar fashion to method resolution with a + // probe phase } } diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h index b607fbe..13b6c91 100644 --- a/gcc/rust/resolve/rust-ast-verify-assignee.h +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -57,7 +57,8 @@ public: void visit (AST::IdentifierExpr &expr) override { - if (!resolver->get_name_scope ().lookup (expr.as_string (), &resolved_node)) + if (!resolver->get_name_scope ().lookup (CanonicalPath (expr.as_string ()), + &resolved_node)) return; ok = true; diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h index 9c01d47..205c877 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -26,6 +26,62 @@ namespace Rust { namespace Resolver { +// https://doc.rust-lang.org/reference/paths.html#canonical-paths +// +// struct X - path X +// impl X { fn test - path X::test } +// +// struct X<T> - path X +// +// impl X<T> { fn test - path X::test} +// impl X<i32> { fn test - path X<i32>::test } +// impl X<f32> { fn test - path X<f32>::test } +class CanonicalPath +{ +public: + explicit CanonicalPath (std::string path) : path (path) {} + + CanonicalPath (const CanonicalPath &other) : path (other.path) {} + + CanonicalPath &operator= (const CanonicalPath &other) + { + path = other.path; + return *this; + } + + std::string get () const { return path; } + + static CanonicalPath get_big_self () { return CanonicalPath ("Self"); } + + static CanonicalPath get_wee_self () { return CanonicalPath ("self"); } + + static CanonicalPath create_empty () + { + return CanonicalPath (std::string ()); + } + + bool is_error () const { return path.empty (); } + + CanonicalPath append (const CanonicalPath &other) const + { + rust_assert (!other.is_error ()); + return is_error () ? CanonicalPath (other.get ()) + : CanonicalPath (append (other.get ())); + } + + bool operator== (const CanonicalPath &b) const + { + return get ().compare (b.get ()) == 0; + } + + bool operator< (const CanonicalPath &b) const { return get () < b.get (); } + +private: + std::string append (std::string elem) const { return path + "::" + elem; } + + std::string path; +}; + class Rib { public: @@ -37,10 +93,11 @@ public: ~Rib () {} - void insert_name (std::string ident, NodeId id, Location locus, bool shadow, - std::function<void (std::string, NodeId, Location)> dup_cb) + void insert_name ( + const CanonicalPath &path, NodeId id, Location locus, bool shadow, + std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb) { - auto it = mappings.find (ident); + auto it = mappings.find (path); bool already_exists = it != mappings.end (); if (already_exists && !shadow) { @@ -48,20 +105,20 @@ public: { if (decl.first == it->second) { - dup_cb (ident, it->second, decl.second); + dup_cb (path, it->second, decl.second); return; } } - dup_cb (ident, it->second, locus); + dup_cb (path, it->second, locus); return; } - mappings[ident] = id; + mappings[path] = id; decls_within_rib.insert (std::pair<NodeId, Location> (id, locus)); references[id] = {}; } - bool lookup_name (std::string ident, NodeId *id) + bool lookup_name (const CanonicalPath &ident, NodeId *id) { auto it = mappings.find (ident); if (it == mappings.end ()) @@ -71,7 +128,7 @@ public: return true; } - void clear_name (std::string ident, NodeId id) + void clear_name (const CanonicalPath &ident, NodeId id) { mappings.erase (ident); for (auto &it : decls_within_rib) @@ -136,7 +193,7 @@ public: private: CrateNum crate_num; NodeId node_id; - std::map<std::string, NodeId> mappings; + std::map<CanonicalPath, NodeId> mappings; std::set<std::pair<NodeId, Location> > decls_within_rib; std::map<NodeId, std::set<NodeId> > references; }; @@ -145,21 +202,24 @@ class Scope { public: Scope (CrateNum crate_num) : crate_num (crate_num) {} + ~Scope () {} - void insert (std::string ident, NodeId id, Location locus, bool shadow, - std::function<void (std::string, NodeId, Location)> dup_cb) + void + insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb) { peek ()->insert_name (ident, id, locus, shadow, dup_cb); } - void insert (std::string ident, NodeId id, Location locus) + void insert (const CanonicalPath &ident, NodeId id, Location locus) { peek ()->insert_name (ident, id, locus, true, - [] (std::string, NodeId, Location) -> void {}); + [] (const CanonicalPath &, NodeId, Location) -> void { + }); } - bool lookup (std::string ident, NodeId *id) + bool lookup (const CanonicalPath &ident, NodeId *id) { NodeId lookup = UNKNOWN_NODEID; iterate ([&] (Rib *r) mutable -> bool { diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h new file mode 100644 index 0000000..b0071c3 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h @@ -0,0 +1,220 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H +#define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H + +#include "rust-hir-type-check-base.h" +#include "rust-hir-full.h" + +namespace Rust { +namespace Resolver { + +class InherentImplItemToName : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static bool resolve (HIR::InherentImplItem *item, std::string &name_result) + { + InherentImplItemToName resolver (name_result); + item->accept_vis (resolver); + return resolver.ok; + } + + void visit (HIR::Method &method) override + { + ok = true; + result.assign (method.get_method_name ()); + } + + void visit (HIR::Function &function) override + { + ok = true; + result.assign (function.get_function_name ()); + } + + void visit (HIR::ConstantItem &constant) override + { + ok = true; + result.assign (constant.get_identifier ()); + } + +private: + InherentImplItemToName (std::string &result) + : TypeCheckBase (), ok (false), result (result) + {} + + bool ok; + std::string &result; +}; + +class GetLocusFromImplItem : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static bool Resolve (HIR::InherentImplItem *query, Location &locus) + { + GetLocusFromImplItem resolver (locus); + query->accept_vis (resolver); + return resolver.ok; + } + + void visit (HIR::ConstantItem &constant) override + { + ok = true; + locus = constant.get_locus (); + } + + void visit (HIR::Function &function) override + { + ok = true; + locus = function.get_locus (); + } + + void visit (HIR::Method &method) override + { + ok = true; + locus = method.get_locus (); + } + +private: + GetLocusFromImplItem (Location &locus) + : TypeCheckBase (), ok (false), locus (locus) + {} + + bool ok; + Location &locus; +}; + +class OverlappingImplItemPass : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static void go () + { + OverlappingImplItemPass pass; + + // generate mappings + pass.mappings->iterate_impl_items ([&] (HirId id, + HIR::InherentImplItem *impl_item, + HIR::InherentImpl *impl) -> bool { + pass.process_impl_item (id, impl_item, impl); + return true; + }); + + pass.scan (); + } + + void process_impl_item (HirId id, HIR::InherentImplItem *impl_item, + HIR::InherentImpl *impl) + { + // lets make a mapping of impl-item Self type to (impl-item,name): + // { + // impl-type -> [ (item, name), ... ] + // } + + HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid (); + TyTy::BaseType *impl_type = nullptr; + bool ok = context->lookup_type (impl_type_id, &impl_type); + rust_assert (ok); + + std::string impl_item_name; + ok = InherentImplItemToName::resolve (impl_item, impl_item_name); + rust_assert (ok); + + std::pair<HIR::InherentImplItem *, std::string> elem (impl_item, + impl_item_name); + impl_mappings[impl_type].insert (std::move (elem)); + } + + void scan () + { + // we can now brute force the map looking for can_eq on each of the + // impl_items_types to look for possible colliding impl blocks; + for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++) + { + TyTy::BaseType *query = it->first; + + for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++) + { + TyTy::BaseType *candidate = iy->first; + if (query == candidate) + continue; + + if (query->can_eq (candidate)) + possible_collision (it->second, iy->second); + } + } + } + + void possible_collision ( + std::set<std::pair<HIR::InherentImplItem *, std::string> > query, + std::set<std::pair<HIR::InherentImplItem *, std::string> > candidate) + { + for (auto &q : query) + { + HIR::InherentImplItem *query_impl_item = q.first; + std::string query_impl_item_name = q.second; + + for (auto &c : candidate) + { + HIR::InherentImplItem *candidate_impl_item = c.first; + std::string candidate_impl_item_name = c.second; + + if (query_impl_item_name.compare (candidate_impl_item_name) == 0) + collision_detected (query_impl_item, candidate_impl_item, + candidate_impl_item_name); + } + } + } + + void collision_detected (HIR::InherentImplItem *query, + HIR::InherentImplItem *dup, const std::string &name) + { + Location qlocus; + bool ok = GetLocusFromImplItem::Resolve (query, qlocus); + rust_assert (ok); + + Location dlocus; + ok = GetLocusFromImplItem::Resolve (dup, dlocus); + rust_assert (ok); + + // this needs GCC Rich locations see + // https://github.com/Rust-GCC/gccrs/issues/97 + rust_error_at (qlocus, "duplicate definitions with name %s", name.c_str ()); + rust_error_at (dlocus, "duplicate def associated with"); + } + +private: + OverlappingImplItemPass () : TypeCheckBase () {} + + std::map<TyTy::BaseType *, + std::set<std::pair<HIR::InherentImplItem *, std::string> > > + impl_mappings; + + std::map<TyTy::BaseType *, std::set<TyTy::BaseType *> > + possible_colliding_impls; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H diff --git a/gcc/rust/typecheck/rust-hir-method-resolve.h b/gcc/rust/typecheck/rust-hir-method-resolve.h index ca5dbe5..b2391e3 100644 --- a/gcc/rust/typecheck/rust-hir-method-resolve.h +++ b/gcc/rust/typecheck/rust-hir-method-resolve.h @@ -22,6 +22,7 @@ #include "rust-hir-type-check-base.h" #include "rust-hir-full.h" #include "rust-tyty.h" +#include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" namespace Rust { @@ -32,73 +33,32 @@ class MethodResolution : public TypeCheckBase using Rust::Resolver::TypeCheckBase::visit; public: - static std::vector<HIR::Method *> Probe (TyTy::BaseType *receiver, - HIR::PathExprSegment method_name) + static std::vector<PathProbeCandidate> + Probe (std::vector<PathProbeCandidate> &path_candidates) { - MethodResolution probe (receiver, method_name); + MethodResolution probe; + for (auto &c : path_candidates) + probe.process_candidate (c); - // lookup impl items for this crate and find all methods that can resolve to - // this receiver - probe.mappings->iterate_impl_items ( - [&] (HirId id, HIR::InherentImplItem *item) mutable -> bool { - item->accept_vis (probe); - return true; - }); - - return probe.probed; + return probe.candidates; } - void visit (HIR::Method &method) override + void process_candidate (PathProbeCandidate &candidate) { - TyTy::BaseType *self_lookup = nullptr; - if (!context->lookup_type ( - method.get_self_param ().get_mappings ().get_hirid (), &self_lookup)) - { - rust_error_at (method.get_self_param ().get_locus (), - "failed to lookup lookup self type in MethodProbe"); - return; - } - - // are the names the same - HIR::PathIdentSegment seg = method_name.get_segment (); - if (seg.as_string ().compare (method.get_method_name ()) != 0) - { - // if the method name does not match then this is not a valid match - return; - } - - if (self_lookup->get_kind () != receiver->get_kind ()) - return; - - if (receiver->has_subsititions_defined () - != self_lookup->has_subsititions_defined ()) - return; - - if (self_lookup->has_subsititions_defined ()) - { - // we assume the receiver should be fully substituted at this stage - self_lookup = SubstMapperFromExisting::Resolve (receiver, self_lookup); - } - - if (!receiver->is_equal (*self_lookup)) - { - // incompatible self argument then this is not a valid method for this - // receiver - return; - } - - probed.push_back (&method); + is_method_flag = false; + candidate.impl_item->accept_vis (*this); + + if (is_method_flag) + candidates.push_back (candidate); } -private: - MethodResolution (TyTy::BaseType *receiver, HIR::PathExprSegment method_name) - : TypeCheckBase (), receiver (receiver), method_name (method_name) - {} + void visit (HIR::Method &method) override { is_method_flag = true; } - TyTy::BaseType *receiver; - HIR::PathExprSegment method_name; +private: + MethodResolution () : TypeCheckBase () {} - std::vector<HIR::Method *> probed; + bool is_method_flag; + std::vector<PathProbeCandidate> candidates; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h new file mode 100644 index 0000000..a838565 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -0,0 +1,162 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_HIR_PATH_PROBE_H +#define RUST_HIR_PATH_PROBE_H + +#include "rust-hir-type-check-base.h" +#include "rust-hir-full.h" +#include "rust-tyty.h" +#include "rust-substitution-mapper.h" + +namespace Rust { +namespace Resolver { + +struct PathProbeCandidate +{ + HIR::InherentImplItem *impl_item; + TyTy::BaseType *ty; +}; + +class PathProbeType : public TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static std::vector<PathProbeCandidate> + Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name) + { + PathProbeType probe (receiver, segment_name); + probe.mappings->iterate_impl_items ( + [&] (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) mutable -> bool { + probe.process_candidate (id, item, impl); + return true; + }); + return probe.candidates; + } + + void process_candidate (HirId id, HIR::InherentImplItem *item, + HIR::InherentImpl *impl) + { + HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); + TyTy::BaseType *impl_block_ty = nullptr; + bool ok = context->lookup_type (impl_ty_id, &impl_block_ty); + rust_assert (ok); + + if (!receiver->can_eq (impl_block_ty)) + return; + + // lets visit the impl_item + item->accept_vis (*this); + } + + void visit (HIR::ConstantItem &constant) override + { + Identifier name = constant.get_identifier (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = constant.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&constant, ty}; + candidates.push_back (std::move (candidate)); + } + } + + void visit (HIR::Function &function) override + { + Identifier name = function.get_function_name (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = function.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&function, ty}; + candidates.push_back (std::move (candidate)); + } + } + + void visit (HIR::Method &method) override + { + Identifier name = method.get_method_name (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = method.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate candidate{&method, ty}; + candidates.push_back (std::move (candidate)); + } + } + +private: + PathProbeType (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query) + : TypeCheckBase (), receiver (receiver), search (query) + {} + + TyTy::BaseType *receiver; + const HIR::PathIdentSegment &search; + std::vector<PathProbeCandidate> candidates; +}; + +class ReportMultipleCandidateError : private TypeCheckBase +{ + using Rust::Resolver::TypeCheckBase::visit; + +public: + static void Report (std::vector<PathProbeCandidate> &candidates, + const HIR::PathIdentSegment &query, Location query_locus) + { + rust_error_at (query_locus, "multiple applicable items in scope for: %s", + query.as_string ().c_str ()); + + ReportMultipleCandidateError visitor; + for (auto &c : candidates) + c.impl_item->accept_vis (visitor); + } + + void visit (HIR::ConstantItem &constant) override + { + rust_error_at (constant.get_locus (), "possible candidate"); + } + + void visit (HIR::Function &function) override + { + rust_error_at (function.get_locus (), "possible candidate"); + } + + void visit (HIR::Method &method) override + { + rust_error_at (method.get_locus (), "possible candidate"); + } + +private: + ReportMultipleCandidateError () : TypeCheckBase () {} +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_PATH_PROBE_H diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 6e7dff8..cb2f250 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -25,6 +25,7 @@ #include "rust-tyty-call.h" #include "rust-hir-type-check-struct-field.h" #include "rust-hir-method-resolve.h" +#include "rust-hir-path-probe.h" #include "rust-substitution-mapper.h" namespace Rust { @@ -171,8 +172,6 @@ public: { TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr (), false); - if (function_tyty == nullptr) - return; bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::ADT || function_tyty->get_kind () == TyTy::TypeKind::FNDEF @@ -211,34 +210,37 @@ public: // which is simple. There will need to be adjustments to ensure we can turn // the receiver into borrowed references etc - auto probes - = MethodResolution::Probe (receiver_tyty, expr.get_method_name ()); - if (probes.size () == 0) + auto candidates + = PathProbeType::Probe (receiver_tyty, + expr.get_method_name ().get_segment ()); + if (candidates.size () == 0) { rust_error_at (expr.get_locus (), "failed to resolve the PathExprSegment to any Method"); return; } - else if (probes.size () > 1) + + // filter all methods + auto possible_methods = MethodResolution::Probe (candidates); + if (possible_methods.size () == 0) { - rust_error_at ( - expr.get_locus (), - "multiple candidates in MethodCallExpr have been probed is " - "not currently supported"); + rust_error_at (expr.get_method_name ().get_locus (), + "no method named %s found in scope", + expr.get_method_name ().as_string ().c_str ()); return; } - - auto resolved_method = probes.at (0); - TyTy::BaseType *lookup_tyty; - if (!context->lookup_type (resolved_method->get_mappings ().get_hirid (), - &lookup_tyty)) + else if (possible_methods.size () > 1) { - rust_error_at (resolved_method->get_locus (), - "failed to lookup type for CallExpr: %s", - expr.as_string ().c_str ()); + ReportMultipleCandidateError::Report ( + possible_methods, expr.get_method_name ().get_segment (), + expr.get_method_name ().get_locus ()); return; } + auto resolved_candidate = possible_methods.at (0); + HIR::InherentImplItem *resolved_method = resolved_candidate.impl_item; + TyTy::BaseType *lookup_tyty = resolved_candidate.ty; + TyTy::BaseType *lookup = lookup_tyty; if (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF) { @@ -271,7 +273,7 @@ public: // set up the resolved name on the path resolver->insert_resolved_name ( expr.get_mappings ().get_nodeid (), - resolved_method->get_mappings ().get_nodeid ()); + resolved_method->get_impl_mappings ().get_nodeid ()); // return the result of the function back infered = function_ret_tyty; @@ -759,80 +761,93 @@ public: void visit (HIR::PathInExpression &expr) override { - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + // resolve root_segment + TyTy::BaseType *tyseg = resolve_root_path (expr); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + else if (expr.get_num_segments () == 1) + { + infered = tyseg; + return; + } - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + NodeId resolved_node_id = UNKNOWN_NODEID; + for (size_t i = 1; i < expr.get_num_segments (); i++) { - // these ref_node_ids will resolve to a pattern declaration but we are - // interested in the definition that this refers to get the parent id - Definition def; - if (!resolver->lookup_definition (ref_node_id, &def)) + HIR::PathExprSegment &seg = expr.get_segments ().at (i); + + // probe the path + auto candidates = PathProbeType::Probe (tyseg, seg.get_segment ()); + if (candidates.size () == 0) { - rust_error_at (expr.get_locus (), - "unknown reference for resolved name"); + rust_error_at (seg.get_locus (), "failed to resolve path segment"); + return; + } + else if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg.get_segment (), + seg.get_locus ()); return; } - ref_node_id = def.parent; - } - else if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup type reference for node: %s", - expr.as_string ().c_str ()); - return; - } - if (ref_node_id == UNKNOWN_NODEID) - { - rust_error_at (expr.get_locus (), "unresolved node: %s", - expr.as_string ().c_str ()); - return; - } + auto candidate = candidates.at (0); + tyseg = candidate.ty; + resolved_node_id + = candidate.impl_item->get_impl_mappings ().get_nodeid (); - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; + bool did_substitute = false; + if (seg.has_generic_args ()) + { + if (!tyseg->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + tyseg->as_string ().c_str ()); + return; + } + + did_substitute = true; + tyseg = SubstMapper::Resolve (tyseg, expr.get_locus (), + &seg.get_generic_args ()); + + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else + { + if (tyseg->needs_generic_substitutions ()) + { + did_substitute = true; + tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ()); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; + } + } } - if (!context->lookup_type (ref, &infered)) + rust_assert (resolved_node_id != UNKNOWN_NODEID); + + // lookup if the name resolver was able to canonically resolve this or not + NodeId path_resolved_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "failed to resolve PathInExpression type"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!infered->supports_substitutions () && seg.has_generic_args ()) + // check the type scope + else if (resolver->lookup_resolved_type (expr.get_mappings ().get_nodeid (), + &path_resolved_id)) { - rust_error_at (expr.get_locus (), - "path does not support substitutions"); - return; + rust_assert (path_resolved_id == resolved_node_id); } - - if (expr.is_self ()) - return; - - if (infered->has_subsititions_defined ()) + else { - if (!infered->can_substitute ()) - { - rust_error_at (expr.get_locus (), - "substitutions not supported for %s", - infered->as_string ().c_str ()); - return; - } - - infered = SubstMapper::Resolve (infered, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); } + + infered = tyseg; } void visit (HIR::LoopExpr &expr) override @@ -951,6 +966,75 @@ private: inside_loop (inside_loop) {} + TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr) + { + HIR::PathExprSegment &root = expr.get_root_seg (); + NodeId ast_node_id = root.get_mappings ().get_nodeid (); + + // then lookup the reference_node_id + NodeId ref_node_id = UNKNOWN_NODEID; + if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + // these ref_node_ids will resolve to a pattern declaration but we are + // interested in the definition that this refers to get the parent id + Definition def; + if (!resolver->lookup_definition (ref_node_id, &def)) + { + rust_error_at (expr.get_locus (), + "unknown reference for resolved name"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + ref_node_id = def.parent; + } + else + { + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + } + + if (ref_node_id == UNKNOWN_NODEID) + { + rust_error_at (root.get_locus (), + "failed to type resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // node back to HIR + HirId ref; + if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), + ref_node_id, &ref)) + { + rust_error_at (expr.get_locus (), "reverse lookup failure"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + TyTy::BaseType *lookup = nullptr; + if (!context->lookup_type (ref, &lookup)) + { + rust_error_at (expr.get_locus (), "failed to resolve root segment"); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); + } + + // turbo-fish segment path::<ty> + if (root.has_generic_args ()) + { + if (!lookup->can_substitute ()) + { + rust_error_at (expr.get_locus (), + "substitutions not supported for %s", + lookup->as_string ().c_str ()); + return new TyTy::ErrorType (lookup->get_ref ()); + } + lookup = SubstMapper::Resolve (lookup, expr.get_locus (), + &root.get_generic_args ()); + } + else if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); + } + + return lookup; + } + bool validate_arithmetic_type (TyTy::BaseType *type, HIR::ArithmeticOrLogicalExpr::ExprType expr_type) diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 68becd4..e52368a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -58,7 +58,7 @@ public: { init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr (), inside_loop); - if (init_expr_ty == nullptr) + if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; init_expr_ty = init_expr_ty->clone (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index 3a6cdc7..8124f35 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -41,8 +41,6 @@ public: void visit (HIR::StructExprStructFields &struct_expr) override; - void visit (HIR::PathInExpression &path) override; - void visit (HIR::StructExprFieldIdentifierValue &field) override; void visit (HIR::StructExprFieldIndexValue &field) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 8b2f657..c8394c8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-item.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-struct-field.h" +#include "rust-hir-inherent-impl-overlap.h" extern bool saw_errors (void); @@ -38,15 +39,21 @@ TypeResolution::Resolve (HIR::Crate &crate) if (saw_errors ()) return; + OverlappingImplItemPass::go (); + if (saw_errors ()) + return; + for (auto it = crate.items.begin (); it != crate.items.end (); it++) TypeCheckItem::Resolve (it->get ()); if (saw_errors ()) return; + auto resolver = Resolver::Resolver::get (); auto mappings = Analysis::Mappings::get (); auto context = TypeCheckContext::get (); + // default inference variables if possible context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool { if (ty->get_kind () == TyTy::TypeKind::ERROR) { @@ -58,24 +65,58 @@ TypeResolution::Resolve (HIR::Crate &crate) // nothing to do if (ty->get_kind () != TyTy::TypeKind::INFER) return true; + TyTy::InferType *infer_var = (TyTy::InferType *) ty; TyTy::BaseType *default_type; bool ok = infer_var->default_type (&default_type); - if (!ok) + if (ok) { - rust_error_at (mappings->lookup_location (id), - "unable to determine type: please give this a type: %u", - id); - return true; + auto result = ty->unify (default_type); + result->set_ref (id); + context->insert_type ( + Analysis::NodeMapping (mappings->get_current_crate (), 0, id, + UNKNOWN_LOCAL_DEFID), + result); } - auto result = ty->unify (default_type); - result->set_ref (id); - context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), - 0, id, UNKNOWN_LOCAL_DEFID), - result); return true; }); + + // scan the ribs to ensure the decls are all setup correctly + resolver->iterate_name_ribs ([&] (Rib *r) -> bool { + r->iterate_decls ([&] (NodeId decl_node_id, Location locus) -> bool { + Definition def; + if (!resolver->lookup_definition (decl_node_id, &def)) + { + rust_error_at (locus, "failed to lookup decl def"); + return true; + } + + HirId hir_node = UNKNOWN_HIRID; + if (!mappings->lookup_node_to_hir (mappings->get_current_crate (), + def.parent, &hir_node)) + { + rust_error_at (locus, "failed to lookup type hir node id"); + return true; + } + + // lookup the ty + TyTy::BaseType *ty = nullptr; + bool ok = context->lookup_type (hir_node, &ty); + if (!ok) + { + rust_error_at (locus, "failed to lookup type for decl node_id: %u", + decl_node_id); + return true; + } + + if (!ty->is_concrete ()) + rust_error_at (locus, "unable to determine type"); + + return true; + }); + return true; + }); } // RUST_HIR_TYPE_CHECK_EXPR @@ -127,14 +168,16 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) void TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) { - struct_expr.get_struct_name ().accept_vis (*this); - if (struct_path_resolved == nullptr) + TyTy::BaseType *struct_path_ty + = TypeCheckExpr::Resolve (&struct_expr.get_struct_name (), false); + if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT) { - rust_fatal_error (struct_expr.get_struct_name ().get_locus (), - "Failed to resolve type"); + rust_error_at (struct_expr.get_struct_name ().get_locus (), + "expected an ADT type for constructor"); return; } + struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty); TyTy::ADTType *struct_def = struct_path_resolved; if (struct_expr.has_struct_base ()) { @@ -258,78 +301,6 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr) } void -TypeCheckStructExpr::visit (HIR::PathInExpression &expr) -{ - NodeId ast_node_id = expr.get_mappings ().get_nodeid (); - - // then lookup the reference_node_id - NodeId ref_node_id; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) - { - rust_error_at (expr.get_locus (), - "Failed to lookup reference for node: %s", - expr.as_string ().c_str ()); - return; - } - } - - // node back to HIR - HirId ref; - if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (), - ref_node_id, &ref)) - { - rust_error_at (expr.get_locus (), "reverse lookup failure"); - return; - } - - // the base reference for this name _must_ have a type set - TyTy::BaseType *lookup; - if (!context->lookup_type (ref, &lookup)) - { - rust_error_at (mappings->lookup_location (ref), - "consider giving this a type: %s", - expr.as_string ().c_str ()); - return; - } - - if (lookup->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected an ADT type"); - return; - } - - struct_path_resolved = static_cast<TyTy::ADTType *> (lookup); - if (struct_path_resolved->has_substitutions ()) - { - HIR::PathExprSegment seg = expr.get_final_segment (); - if (!struct_path_resolved->needs_substitution () - && seg.has_generic_args ()) - { - rust_error_at (seg.get_generic_args ().get_locus (), - "unexpected type arguments"); - } - else if (struct_path_resolved->needs_substitution ()) - { - TyTy::BaseType *subst - = SubstMapper::Resolve (struct_path_resolved, expr.get_locus (), - seg.has_generic_args () - ? &seg.get_generic_args () - : nullptr); - if (subst == nullptr || subst->get_kind () != TyTy::TypeKind::ADT) - { - rust_fatal_error (mappings->lookup_location (ref), - "expected a substituted ADT type"); - return; - } - struct_path_resolved = static_cast<TyTy::ADTType *> (subst); - } - } -} - -void TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) { auto it = fields_assigned.find (field.field_name); diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index d449c72..db43cbd 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -37,6 +37,11 @@ public: return mapper.resolved; } + static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus) + { + return SubstMapper::Resolve (base, locus, nullptr); + } + bool have_generic_args () const { return generics != nullptr; } void visit (TyTy::FnType &type) override diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h new file mode 100644 index 0000000..e2e0d08 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -0,0 +1,812 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_TYTY_CMP_H +#define RUST_TYTY_CMP_H + +#include "rust-diagnostics.h" +#include "rust-tyty.h" +#include "rust-tyty-visitor.h" +#include "rust-hir-map.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace TyTy { + +class BaseCmp : public TyVisitor +{ +public: + virtual bool can_eq (BaseType *other) + { + if (other->get_kind () == TypeKind::PARAM) + { + ParamType *p = static_cast<ParamType *> (other); + if (p->can_resolve ()) + { + other = p->resolve (); + } + } + + other->accept_vis (*this); + return ok; + } + + virtual void visit (TupleType &) override { ok = false; } + + virtual void visit (ADTType &) override { ok = false; } + + virtual void visit (InferType &) override { ok = false; } + + virtual void visit (FnType &) override { ok = false; } + + virtual void visit (FnPtr &) override { ok = false; } + + virtual void visit (ArrayType &) override { ok = false; } + + virtual void visit (BoolType &) override { ok = false; } + + virtual void visit (IntType &) override { ok = false; } + + virtual void visit (UintType &) override { ok = false; } + + virtual void visit (USizeType &) override { ok = false; } + + virtual void visit (ISizeType &) override { ok = false; } + + virtual void visit (FloatType &) override { ok = false; } + + virtual void visit (ErrorType &) override { ok = false; } + + virtual void visit (CharType &) override { ok = false; } + + virtual void visit (ReferenceType &) override { ok = false; } + + virtual void visit (ParamType &) override + { + // it is ok for types to can eq to a ParamType + ok = true; + } + + virtual void visit (StrType &) override { ok = false; } + +protected: + BaseCmp (BaseType *base) + : mappings (Analysis::Mappings::get ()), + context (Resolver::TypeCheckContext::get ()), ok (false) + {} + + Analysis::Mappings *mappings; + Resolver::TypeCheckContext *context; + + bool ok; + +private: + /* Returns a pointer to the ty that created this rule. */ + virtual BaseType *get_base () = 0; +}; + +class InferCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + InferCmp (InferType *base) : BaseCmp (base), base (base) {} + + void visit (BoolType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (IntType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (UintType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (USizeType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ISizeType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (FloatType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) + || (base->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ArrayType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ADTType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (TupleType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (InferType &type) override + { + switch (base->get_infer_kind ()) + { + case InferType::InferTypeKind::GENERAL: + ok = true; + return; + + case InferType::InferTypeKind::INTEGRAL: { + if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) + { + ok = true; + return; + } + else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) + { + ok = true; + return; + } + } + break; + + case InferType::InferTypeKind::FLOAT: { + if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) + { + ok = true; + return; + } + else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) + { + ok = true; + return; + } + } + break; + } + + BaseCmp::visit (type); + } + + void visit (CharType &type) override + { + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + } + + void visit (ReferenceType &type) override + + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + + void visit (ParamType &type) override + { + bool is_valid + = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + { + ok = true; + return; + } + + BaseCmp::visit (type); + } + +private: + BaseType *get_base () override { return base; } + + InferType *base; +}; + +class FnCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FnCmp (FnType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + + void visit (FnType &type) override + { + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto a = base->param_at (i).second; + auto b = type.param_at (i).second; + + auto unified_param = a->unify (b); + if (unified_param == nullptr) + { + BaseCmp::visit (type); + return; + } + } + + auto unified_return + = base->get_return_type ()->unify (type.get_return_type ()); + if (unified_return == nullptr) + { + BaseCmp::visit (type); + return; + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + FnType *base; +}; + +class FnptrCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FnptrCmp (FnPtr *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseCmp::visit (type); + return; + } + + ok = true; + } + + void visit (FnPtr &type) override + { + auto this_ret_type = base->get_return_type (); + auto other_ret_type = type.get_return_type (); + auto unified_result = this_ret_type->unify (other_ret_type); + if (unified_result == nullptr + || unified_result->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto this_param = base->param_at (i); + auto other_param = type.param_at (i); + auto unified_param = this_param->unify (other_param); + if (unified_param == nullptr + || unified_param->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + + void visit (FnType &type) override + { + auto this_ret_type = base->get_return_type (); + auto other_ret_type = type.get_return_type (); + auto unified_result = this_ret_type->unify (other_ret_type); + if (unified_result == nullptr + || unified_result->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + + if (base->num_params () != type.num_params ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_params (); i++) + { + auto this_param = base->param_at (i); + auto other_param = type.param_at (i).second; + auto unified_param = this_param->unify (other_param); + if (unified_param == nullptr + || unified_param->get_kind () == TypeKind::ERROR) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + FnPtr *base; +}; + +class ArrayCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ArrayCmp (ArrayType *base) : BaseCmp (base), base (base) {} + + void visit (ArrayType &type) override + { + // check base type + auto base_resolved + = base->get_element_type ()->unify (type.get_element_type ()); + if (base_resolved == nullptr) + { + BaseCmp::visit (type); + return; + } + + // need to check the base types and capacity + if (type.get_capacity () != base->get_capacity ()) + { + Location locus = mappings->lookup_location (type.get_ref ()); + rust_error_at (locus, "mismatch in array capacity"); + BaseCmp::visit (type); + return; + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + ArrayType *base; +}; + +class BoolCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + BoolCmp (BoolType *base) : BaseCmp (base), base (base) {} + + void visit (BoolType &type) override { ok = true; } + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + +private: + BaseType *get_base () override { return base; } + + BoolType *base; +}; + +class IntCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + IntCmp (IntType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (IntType &type) override + { + ok = type.get_int_kind () == base->get_int_kind (); + } + +private: + BaseType *get_base () override { return base; } + + IntType *base; +}; + +class UintCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + UintCmp (UintType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (UintType &type) override + { + ok = type.get_uint_kind () == base->get_uint_kind (); + } + +private: + BaseType *get_base () override { return base; } + + UintType *base; +}; + +class FloatCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + FloatCmp (FloatType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::INTEGRAL; + } + + void visit (FloatType &type) override + { + ok = type.get_float_kind () == base->get_float_kind (); + } + +private: + BaseType *get_base () override { return base; } + + FloatType *base; +}; + +class ADTCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ADTCmp (ADTType *base) : BaseCmp (base), base (base) {} + + void visit (ADTType &type) override + { + if (base->get_identifier ().compare (type.get_identifier ()) != 0) + { + BaseCmp::visit (type); + return; + } + + if (base->num_fields () != type.num_fields ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < type.num_fields (); ++i) + { + TyTy::StructFieldType *base_field = base->get_field (i); + TyTy::StructFieldType *other_field = type.get_field (i); + + TyTy::BaseType *this_field_ty = base_field->get_field_type (); + TyTy::BaseType *other_field_ty = other_field->get_field_type (); + + if (!this_field_ty->can_eq (other_field_ty)) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + ADTType *base; +}; + +class TupleCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + TupleCmp (TupleType *base) : BaseCmp (base), base (base) {} + + void visit (TupleType &type) override + { + if (base->num_fields () != type.num_fields ()) + { + BaseCmp::visit (type); + return; + } + + for (size_t i = 0; i < base->num_fields (); i++) + { + BaseType *bo = base->get_field (i); + BaseType *fo = type.get_field (i); + + if (!bo->can_eq (fo)) + { + BaseCmp::visit (type); + return; + } + } + + ok = true; + } + +private: + BaseType *get_base () override { return base; } + + TupleType *base; +}; + +class USizeCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + USizeCmp (USizeType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (USizeType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + USizeType *base; +}; + +class ISizeCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ISizeCmp (ISizeType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () != InferType::InferTypeKind::FLOAT; + } + + void visit (ISizeType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + ISizeType *base; +}; + +class CharCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + CharCmp (CharType *base) : BaseCmp (base), base (base) {} + + void visit (InferType &type) override + { + ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL; + } + + void visit (CharType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + CharType *base; +}; + +class ReferenceCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ReferenceCmp (ReferenceType *base) : BaseCmp (base), base (base) {} + + void visit (ReferenceType &type) override + { + auto base_type = base->get_base (); + auto other_base_type = type.get_base (); + + ok = base_type->can_eq (other_base_type); + } + +private: + BaseType *get_base () override { return base; } + + ReferenceType *base; +}; + +class ParamCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ParamCmp (ParamType *base) : BaseCmp (base), base (base) {} + + // param types are a placeholder we shouldn't have cases where we unify + // against it. eg: struct foo<T> { a: T }; When we invoke it we can do either: + // + // foo<i32>{ a: 123 }. + // Then this enforces the i32 type to be referenced on the + // field via an hirid. + // + // rust also allows for a = foo{a:123}; Where we can use an Inference Variable + // to handle the typing of the struct + bool can_eq (BaseType *other) override final + { + if (base->get_ref () == base->get_ty_ref ()) + return BaseCmp::can_eq (other); + + auto context = Resolver::TypeCheckContext::get (); + BaseType *lookup = nullptr; + bool ok = context->lookup_type (base->get_ty_ref (), &lookup); + rust_assert (ok); + + return lookup->can_eq (other); + } + + void visit (ParamType &type) override + { + ok = base->get_symbol ().compare (type.get_symbol ()) == 0; + } + +private: + BaseType *get_base () override { return base; } + + ParamType *base; +}; + +class StrCmp : public BaseCmp +{ + // FIXME we will need a enum for the StrType like ByteBuf etc.. + using Rust::TyTy::BaseCmp::visit; + +public: + StrCmp (StrType *base) : BaseCmp (base), base (base) {} + + void visit (StrType &type) override { ok = true; } + +private: + BaseType *get_base () override { return base; } + + StrType *base; +}; + +} // namespace TyTy +} // namespace Rust + +#endif // RUST_TYTY_CMP_H diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h index 0fb04c5..c23cbc1 100644 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ b/gcc/rust/typecheck/rust-tyty-rules.h @@ -67,8 +67,8 @@ public: } other->accept_vis (*this); - if (resolved == nullptr) - return nullptr; + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + return resolved; resolved->append_reference (get_base ()->get_ref ()); resolved->append_reference (other->get_ref ()); @@ -81,7 +81,7 @@ public: bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER; bool results_is_non_general_infer_var = (result_is_infer_var - && ((InferType *) resolved)->get_infer_kind () + && (static_cast<InferType *> (resolved))->get_infer_kind () != TyTy::InferType::GENERAL); if (result_resolved || results_is_non_general_infer_var) { @@ -229,7 +229,7 @@ public: virtual void visit (ParamType &type) override { Location ref_locus = mappings->lookup_location (type.get_ref ()); - rust_error_at (ref_locus, "expected [%s] got [ParamTy <%s>]", + rust_error_at (ref_locus, "expected [%s] got [%s]", get_base ()->as_string ().c_str (), type.as_string ().c_str ()); } @@ -829,6 +829,12 @@ public: void visit (ADTType &type) override { + if (base->get_identifier ().compare (type.get_identifier ()) != 0) + { + BaseRules::visit (type); + return; + } + if (base->num_fields () != type.num_fields ()) { BaseRules::visit (type); @@ -844,11 +850,8 @@ public: TyTy::BaseType *other_field_ty = other_field->get_field_type (); BaseType *unified_ty = this_field_ty->unify (other_field_ty); - if (unified_ty == nullptr) - { - BaseRules::visit (type); - return; - } + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + return; } resolved = type.clone (); @@ -882,11 +885,8 @@ public: BaseType *fo = type.get_field (i); BaseType *unified_ty = bo->unify (fo); - if (unified_ty == nullptr) - { - BaseRules::visit (type); - return; - } + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + return; fields.push_back (TyVar (unified_ty->get_ref ())); } @@ -1034,6 +1034,7 @@ public: { if (base->get_ref () == base->get_ty_ref ()) return BaseRules::unify (other); + auto context = Resolver::TypeCheckContext::get (); BaseType *lookup = nullptr; bool ok = context->lookup_type (base->get_ty_ref (), &lookup); @@ -1053,6 +1054,17 @@ public: resolved = type.clone (); } + void visit (InferType &type) override + { + if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) + { + BaseRules::visit (type); + return; + } + + resolved = base->clone (); + } + private: BaseType *get_base () override { return base; } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index cb0543c..8f2faec 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-tyty-rules.h" +#include "rust-tyty-cmp.h" #include "rust-hir-map.h" #include "rust-substitution-mapper.h" @@ -91,6 +92,13 @@ InferType::unify (BaseType *other) return r.unify (other); } +bool +InferType::can_eq (BaseType *other) +{ + InferCmp r (this); + return r.can_eq (other); +} + BaseType * InferType::clone () { @@ -107,11 +115,13 @@ InferType::default_type (BaseType **type) const { case GENERAL: return false; + case INTEGRAL: { ok = context->lookup_builtin ("i32", type); rust_assert (ok); return ok; } + case FLOAT: { ok = context->lookup_builtin ("f64", type); rust_assert (ok); @@ -139,6 +149,12 @@ ErrorType::unify (BaseType *other) return this; } +bool +ErrorType::can_eq (BaseType *other) +{ + return get_kind () == other->get_kind (); +} + BaseType * ErrorType::clone () { @@ -304,6 +320,13 @@ ADTType::unify (BaseType *other) } bool +ADTType::can_eq (BaseType *other) +{ + ADTCmp r (this); + return r.can_eq (other); +} + +bool ADTType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -418,8 +441,7 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) BaseType *concrete = Resolver::SubstMapperInternal::Resolve (fty, subst_mappings); - if (concrete == nullptr - || concrete->get_kind () == TyTy::TypeKind::ERROR) + if (concrete->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (subst_mappings.get_locus (), "Failed to resolve field substitution type: %s", @@ -470,6 +492,13 @@ TupleType::unify (BaseType *other) } bool +TupleType::can_eq (BaseType *other) +{ + TupleCmp r (this); + return r.can_eq (other); +} + +bool TupleType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -524,6 +553,13 @@ FnType::unify (BaseType *other) } bool +FnType::can_eq (BaseType *other) +{ + FnCmp r (this); + return r.can_eq (other); +} + +bool FnType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -713,6 +749,13 @@ FnPtr::unify (BaseType *other) } bool +FnPtr::can_eq (BaseType *other) +{ + FnptrCmp r (this); + return r.can_eq (other); +} + +bool FnPtr::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -767,6 +810,13 @@ ArrayType::unify (BaseType *other) } bool +ArrayType::can_eq (BaseType *other) +{ + ArrayCmp r (this); + return r.can_eq (other); +} + +bool ArrayType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -814,6 +864,13 @@ BoolType::unify (BaseType *other) return r.unify (other); } +bool +BoolType::can_eq (BaseType *other) +{ + BoolCmp r (this); + return r.can_eq (other); +} + BaseType * BoolType::clone () { @@ -853,6 +910,13 @@ IntType::unify (BaseType *other) return r.unify (other); } +bool +IntType::can_eq (BaseType *other) +{ + IntCmp r (this); + return r.can_eq (other); +} + BaseType * IntType::clone () { @@ -903,6 +967,13 @@ UintType::unify (BaseType *other) return r.unify (other); } +bool +UintType::can_eq (BaseType *other) +{ + UintCmp r (this); + return r.can_eq (other); +} + BaseType * UintType::clone () { @@ -947,6 +1018,13 @@ FloatType::unify (BaseType *other) return r.unify (other); } +bool +FloatType::can_eq (BaseType *other) +{ + FloatCmp r (this); + return r.can_eq (other); +} + BaseType * FloatType::clone () { @@ -983,6 +1061,13 @@ USizeType::unify (BaseType *other) return r.unify (other); } +bool +USizeType::can_eq (BaseType *other) +{ + USizeCmp r (this); + return r.can_eq (other); +} + BaseType * USizeType::clone () { @@ -1008,6 +1093,13 @@ ISizeType::unify (BaseType *other) return r.unify (other); } +bool +ISizeType::can_eq (BaseType *other) +{ + ISizeCmp r (this); + return r.can_eq (other); +} + BaseType * ISizeType::clone () { @@ -1033,6 +1125,13 @@ CharType::unify (BaseType *other) return r.unify (other); } +bool +CharType::can_eq (BaseType *other) +{ + CharCmp r (this); + return r.can_eq (other); +} + BaseType * CharType::clone () { @@ -1059,6 +1158,13 @@ ReferenceType::unify (BaseType *other) } bool +ReferenceType::can_eq (BaseType *other) +{ + ReferenceCmp r (this); + return r.can_eq (other); +} + +bool ReferenceType::is_equal (const BaseType &other) const { if (get_kind () != other.get_kind ()) @@ -1110,6 +1216,13 @@ ParamType::unify (BaseType *other) return r.unify (other); } +bool +ParamType::can_eq (BaseType *other) +{ + ParamCmp r (this); + return r.can_eq (other); +} + BaseType * ParamType::clone () { @@ -1179,6 +1292,13 @@ StrType::unify (BaseType *other) } bool +StrType::can_eq (BaseType *other) +{ + StrCmp r (this); + return r.can_eq (other); +} + +bool StrType::is_equal (const BaseType &other) const { return get_kind () == other.get_kind (); diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 7b4197f..c428c4c 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -75,15 +75,20 @@ public: virtual std::string get_name () const = 0; - /* Unify two types. Returns a pointer to the newly-created unified ty, or - nullptr if the two ty cannot be unified. The caller is responsible for - releasing the memory of the returned ty. */ + // Unify two types. Returns a pointer to the newly-created unified ty, or + // nullptr if the two ty cannot be unified. The caller is responsible for + // releasing the memory of the returned ty. using ignore_errors alows for a + // can_eq style unification virtual BaseType *unify (BaseType *other) = 0; - /* Check value equality between two ty. Type inference rules are ignored. Two - ty are considered equal if they're of the same kind, and - 1. (For ADTs, arrays, tuples, refs) have the same underlying ty - 2. (For functions) have the same signature */ + // similar to unify but does not actually perform type unification but + // determines whether they are compatible + virtual bool can_eq (BaseType *other) = 0; + + // Check value equality between two ty. Type inference rules are ignored. Two + // ty are considered equal if they're of the same kind, and + // 1. (For ADTs, arrays, tuples, refs) have the same underlying ty + // 2. (For functions) have the same signature virtual bool is_equal (const BaseType &other) const { return get_kind () == other.get_kind (); @@ -91,6 +96,8 @@ public: virtual bool is_unit () const { return false; } + virtual bool is_concrete () const { return true; } + TypeKind get_kind () const { return kind; } /* Returns a pointer to a clone of this. The caller is responsible for @@ -111,6 +118,8 @@ public: return supports_substitutions () && has_subsititions_defined (); } + virtual bool needs_generic_substitutions () const { return false; } + std::string mappings_str () const { std::string buffer = "Ref: " + std::to_string (get_ref ()) @@ -127,7 +136,11 @@ public: return as_string () + ":" + mappings_str (); } - void debug () const { printf ("%s\n", debug_str ().c_str ()); } + void debug () const + { + printf ("[%p] %s\n", static_cast<const void *> (this), + debug_str ().c_str ()); + } protected: BaseType (HirId ref, HirId ty_ref, TypeKind kind, @@ -186,6 +199,8 @@ public: BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; + BaseType *clone () final override; InferTypeKind get_infer_kind () const { return infer_kind; } @@ -194,6 +209,8 @@ public: bool default_type (BaseType **type) const; + bool is_concrete () const final override { return false; } + private: InferTypeKind infer_kind; }; @@ -216,6 +233,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; @@ -242,6 +260,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; @@ -312,6 +331,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -321,6 +341,16 @@ public: BaseType *clone () final override; + bool is_concrete () const override final + { + for (size_t i = 0; i < num_fields (); i++) + { + if (!get_field (i)->is_concrete ()) + return false; + } + return true; + } + void iterate_fields (std::function<bool (BaseType *)> cb) const { for (size_t i = 0; i < num_fields (); i++) @@ -405,6 +435,12 @@ public: static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); } + bool is_conrete () const + { + return argument != nullptr && argument->get_kind () != TyTy::TypeKind::ERROR + && argument->get_kind () != TyTy::TypeKind::PARAM; + } + std::string as_string () const { return param->as_string () + ":" + argument->as_string (); @@ -459,6 +495,19 @@ public: return false; } + // is_concrete means if the used args is non error, ie: non empty this will + // verify if actual real types have been put in place of are they still + // ParamTy + bool is_concrete () const + { + for (auto &mapping : mappings) + { + if (!mapping.is_conrete ()) + return false; + } + return true; + } + Location get_locus () { return locus; } size_t size () const { return mappings.size (); } @@ -529,7 +578,8 @@ public: bool needs_substitution () const { - return has_substitutions () && used_arguments.is_error (); + return has_substitutions () + && (used_arguments.is_error () || !used_arguments.is_concrete ()); } bool was_substituted () const { return !needs_substitution (); } @@ -608,11 +658,14 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; size_t num_fields () const { return fields.size (); } + std::string get_identifier () const { return identifier; } + std::string get_name () const override final { return identifier + subst_as_string (); @@ -657,6 +710,11 @@ public: } } + bool needs_generic_substitutions () const override final + { + return needs_substitution (); + } + bool supports_substitutions () const override final { return true; } bool has_subsititions_defined () const override final @@ -702,6 +760,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -731,6 +790,11 @@ public: BaseType *clone () final override; + bool needs_generic_substitutions () const override final + { + return needs_substitution (); + } + bool supports_substitutions () const override final { return true; } bool has_subsititions_defined () const override final @@ -774,6 +838,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -815,6 +880,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -824,6 +890,11 @@ public: BaseType *clone () final override; + bool is_concrete () const final override + { + return get_element_type ()->is_concrete (); + } + private: size_t capacity; TyVar element_type; @@ -847,6 +918,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -879,6 +951,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; IntKind get_int_kind () const { return int_kind; } @@ -918,6 +991,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; UintKind get_uint_kind () const { return uint_kind; } @@ -955,6 +1029,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; FloatKind get_float_kind () const { return float_kind; } @@ -994,6 +1069,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1026,6 +1102,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1058,6 +1135,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; BaseType *clone () final override; }; @@ -1094,6 +1172,7 @@ public: std::string get_name () const override final { return as_string (); } BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; @@ -1131,6 +1210,7 @@ public: std::string as_string () const override; BaseType *unify (BaseType *other) override; + bool can_eq (BaseType *other) override; bool is_equal (const BaseType &other) const override; diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 891618e..0dcbd4f 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -524,5 +524,24 @@ Mappings::resolve_nodeid_to_stmt (CrateNum crate, NodeId id, HIR::Stmt **stmt) return resolved_stmt != nullptr; } +void +Mappings::iterate_impl_items ( + std::function<bool (HirId, HIR::InherentImplItem *, HIR::InherentImpl *)> cb) +{ + for (auto it = hirImplItemMappings.begin (); it != hirImplItemMappings.end (); + it++) + { + for (auto iy = it->second.begin (); iy != it->second.end (); iy++) + { + auto id = iy->first; + auto impl_item = iy->second.second; + auto impl = lookup_associated_impl ( + impl_item->get_impl_mappings ().get_hirid ()); + if (!cb (id, impl_item, impl)) + return; + } + } +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 2e8a629..9777ee3 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -158,20 +158,24 @@ public: return hirNodesWithinCrate[crate]; } - void - iterate_impl_items (std::function<bool (HirId, HIR::InherentImplItem *)> cb) + void insert_impl_item_mapping (HirId impl_item_id, HIR::InherentImpl *impl) { - for (auto it = hirImplItemMappings.begin (); - it != hirImplItemMappings.end (); it++) - { - for (auto iy = it->second.begin (); iy != it->second.end (); iy++) - { - if (!cb (iy->first, iy->second.second)) - return; - } - } + rust_assert (hirImplItemsToImplMappings.find (impl_item_id) + == hirImplItemsToImplMappings.end ()); + hirImplItemsToImplMappings[impl_item_id] = impl; } + HIR::InherentImpl *lookup_associated_impl (HirId impl_item_id) + { + auto lookup = hirImplItemsToImplMappings.find (impl_item_id); + rust_assert (lookup != hirImplItemsToImplMappings.end ()); + return lookup->second; + } + + void iterate_impl_items ( + std::function<bool (HirId, HIR::InherentImplItem *, HIR::InherentImpl *)> + cb); + private: Mappings (); @@ -198,6 +202,7 @@ private: std::map<HirId, std::pair<HirId, HIR::InherentImplItem *> > > hirImplItemMappings; std::map<CrateNum, std::map<HirId, HIR::SelfParam *> > hirSelfParamMappings; + std::map<HirId, HIR::InherentImpl *> hirImplItemsToImplMappings; // location info std::map<CrateNum, std::map<NodeId, Location> > locations; |