diff options
author | Ian Lance Taylor <iant@golang.org> | 2023-06-21 11:04:04 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2023-06-21 11:04:04 -0700 |
commit | 97e31a0a2a2d2273687fcdb4e5416aab1a2186e1 (patch) | |
tree | d5c1cae4de436a0fe54a5f0a2a197d309f3d654c /gcc/rust | |
parent | 6612f4f8cb9b0d5af18ec69ad04e56debc3e6ced (diff) | |
parent | 577223aebc7acdd31e62b33c1682fe54a622ae27 (diff) | |
download | gcc-97e31a0a2a2d2273687fcdb4e5416aab1a2186e1.zip gcc-97e31a0a2a2d2273687fcdb4e5416aab1a2186e1.tar.gz gcc-97e31a0a2a2d2273687fcdb4e5416aab1a2186e1.tar.bz2 |
Merge from trunk revision 577223aebc7acdd31e62b33c1682fe54a622ae27.
Diffstat (limited to 'gcc/rust')
114 files changed, 11138 insertions, 5667 deletions
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index 72c172e..25b8ddf 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,953 @@ +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h + (Parser::parse_stmt): Handle unsafe expression statements. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h + (Parser::parse_expr_stmt): Remove hypothetical unsafe + expr_stmt_without_block handling. + +2023-04-06 M V V S Manoj Kumar <mvvsmanojkumar@gmail.com> + + * ast/rust-ast-full-decls.h (class InlineAsm):Added class declaration. + * ast/rust-expr.h (class InlineAsm):Added class definition. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-diagnostics.h (struct Error): Add new Kind enum and various new + static constructors to allow for hints as well. + * rust-diagnostics.cc (Error::Error): Use new `kind` field properly. + * checks/errors/privacy/rust-visibility-resolver.cc + (VisibilityResolver::resolve_module_path): Use new Error API. + * expand/rust-macro-builtins.cc (MacroBuiltin::include_handler): Likewise. + * expand/rust-macro-expand.cc (parse_many): Likewise. + (transcribe_type): Likewise. + * parse/rust-parse-impl.h (Parser::parse_crate): Likewise. + * rust-session-manager.cc (Session::handle_crate_name): Likewise. + * ast/rust-ast.cc (Module::load_items): Likewise. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Keep location in TraitItem base class + * ast/rust-item.h (class TraitItemFunc): Use base class location instead. + (class TraitItemMethod): Likewise. + (class TraitItemConst): Likewise. + (class TraitItemType): Likewise. + * ast/rust-macro.h: Likewise. + +2023-04-06 SainiAditya1 <Adityasaini10012001@outlook.com> + + * hir/tree/rust-hir-full-test.cc: Moved to... + * hir/tree/rust-hir.cc: ...here. + * Make-lang.in: Rename rust-hir-full-test. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-dump.cc + (Dump::visit): Add AltPattern visitor. + * ast/rust-ast-dump.h: + (Dump::visit): Add AltPattern visitor. + * ast/rust-ast-full-decls.h + (class AltPattern): Add declaration. + * ast/rust-ast-visitor.h: + (ASTVisitor::visit): Add AltPattern visitor. + * ast/rust-ast.cc + (AltPattern::as_string): Add definition. + (AltPattern::accept_vis): Add definition. + * ast/rust-pattern.h + (class AltPattern): Add declaration. + * checks/errors/rust-feature-gate.h: + (FeatureGate::visit) Add AltPattern visitor + * expand/rust-attribute-visitor.cc + (AttrVisitor::visit): Add AltPattern visitor. + * expand/rust-attribute-visitor.h: + (AttrVisitor::visit): Add AltPattern visitor. + * hir/rust-ast-lower-base.cc + (ASTLoweringBase::visit): Add AltPattern visitor. + * hir/rust-ast-lower-base.h: + (ASTLoweringBase::visit): Add AltPattern visitor. + * resolve/rust-ast-resolve-base.cc + (ResolverBase::visit): Add AltPattern visitor. + * resolve/rust-ast-resolve-base.h: + (ResolverBase::visit): Add AltPattern visitor. + * resolve/rust-early-name-resolver.cc + (EarlyNameResolver::visit): Add AltPattern visitor. + * resolve/rust-early-name-resolver.h: + (EarlyNameResolver::visit): Add AltPattern visitor. + * util/rust-attributes.cc + (AttributeChecker::visit): Add AltPattern visitor. + * util/rust-attributes.h: + (AttributeChecker::visit): Add AltPattern visitor. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-pattern.h: Fix formatting. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-builtins.cc (MacroBuiltin::include_handler): Do not + return nullptr token in expansion of `include!()` + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-feature-gate.h: Add trailing newline before EOF. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.cc (TraitReference::clear_associated_types): make const + (TraitReference::clear_associated_type_projections): new interface + * typecheck/rust-hir-trait-reference.h: + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): refactor + (TraitItemReference::associated_type_reset): reset projections + * typecheck/rust-hir-type-bounds.h: + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): fix bounds + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::TypeBoundsProbe): refactor into cc file + (TypeBoundsProbe::Probe): refactor + (TypeBoundsProbe::is_bound_satisfied_for_type): likewise + (TypeBoundsProbe::assemble_sized_builtin): add builtin for Sized + (TypeCheckBase::get_predicate_from_bound): refactor + (TypeBoundPredicate::lookup_associated_type): refactor + * typecheck/rust-tyty-subst.cc (SubstitutionRef::lookup_associated_impl) + (SubstitutionRef::prepare_higher_ranked_bounds): new interface to clear hanging bounds + (SubstitutionRef::monomorphize): refactor + * typecheck/rust-tyty-subst.h: + * typecheck/rust-tyty.cc (BaseType::get_locus): helper + (BaseType::satisfies_bound): ensure bounds are satisfied and assoicated types + (ParamType::ParamType): new field in constructor + (ParamType::clone): update clone + (ParamType::set_implicit_self_trait): new interface + (ParamType::is_implicit_self_trait): likewise + * typecheck/rust-tyty.h: cleanup + * util/rust-hir-map.cc (Mappings::Mappings): builtin marker + (Mappings::~Mappings): delete marker + (Mappings::lookup_builtin_marker): lookup + * util/rust-hir-map.h: update header + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * hir/tree/rust-hir-item.h: implement virtual function + * hir/tree/rust-hir.h: add virtual function + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: add new dependancy + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::query_type): refactor + * typecheck/rust-hir-type-check-base.h: refactor + * typecheck/rust-hir-type-check.h (RUST_HIR_TYPE_CHECK): refactor + * typecheck/rust-type-util.cc: New file. + * typecheck/rust-type-util.h: New file. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-macro-builtins.cc + (MacroBuiltin::include_str_handler): Add check for valid UTF-8. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h + (Parser::parse_grouped_or_tuple_pattern): Add support for empty tuple patterns. + +2023-04-06 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-lex.h: Add file type check. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-pattern.cc + (CompilePatternLet::visit): Simplify WildcardPattern compilation for let statements. + * backend/rust-compile-var-decl.h: + (CompileVarDecl::visit): Remove variable declaration for WildcardPattern. + * resolve/rust-ast-resolve-pattern.h: + (PatternDeclaration::visit): Remove name resolution for WildcardPattern. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-tyty-call.cc + (TypeCheckCallExpr::visit): Add variadic argument type checking. + (TypeCheckCallExpr::visit): Fix comment spelling ("varadic"). + +2023-04-06 mxlol233 <mxlol233@outlook.com> + + * checks/errors/rust-feature-gate.cc: Add implementation for + `void FeatureGate::visit (AST::ExternBlock &block)`. Add `valid_feature` + construction process in `FeatureGate::check`. + * checks/errors/rust-feature-gate.h: Add declaration for + `void FeatureGate::visit (AST::ExternBlock &block)`. Add private + variable `valid_feature`. + * checks/errors/rust-feature.h: Change `issue` to `m_issue`. + +2023-04-06 Thomas Schwinge <thomas@codesourcery.com> + + * ast/rust-ast-fragment.cc: Update copyright years. + * ast/rust-ast-fragment.h: Likewise. + * ast/rust-macro.cc: Likewise. + * checks/errors/rust-feature-gate.cc: Likewise. + * checks/errors/rust-feature-gate.h: Likewise. + * checks/errors/rust-feature.cc: Likewise. + * checks/errors/rust-feature.h: Likewise. + * hir/rust-ast-lower-expr.cc: Likewise. + * hir/rust-ast-lower-type.cc: Likewise. + * resolve/rust-early-name-resolver.cc: Likewise. + * resolve/rust-early-name-resolver.h: Likewise. + * rust-gcc.h: Likewise. + * typecheck/rust-hir-path-probe.cc: Likewise. + * typecheck/rust-hir-trait-reference.cc: Likewise. + * typecheck/rust-tyty-bounds.h: Likewise. + * typecheck/rust-tyty-subst.cc: Likewise. + * typecheck/rust-tyty-subst.h: Likewise. + * typecheck/rust-tyty-util.cc: Likewise. + * typecheck/rust-tyty-util.h: Likewise. + * typecheck/rust-unify.cc: Likewise. + * typecheck/rust-unify.h: Likewise. + * util/rust-inline-visitor.h: Likewise. + +2023-04-06 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Update the + environment variable name. + +2023-04-06 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * Make-lang.in: Add `rust-hir-trait-reference.o`. + * typecheck/rust-hir-trait-reference.h: Remove multiple function body. + * typecheck/rust-hir-trait-reference.cc: Add multiple function body. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc (MacroExpander::expand_eager_invocations): + Add documentation explaining the algorithm. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-macro.cc: New file. + * Make-lang.in: Add `rust-macro.o` object + * ast/rust-ast-fragment.cc (Fragment::Fragment): Change API around + the construction of AST fragments. + (Fragment::operator=): Correct `Fragment::operator=` to take into + account the fragment tokens. + (Fragment::create_error): Use new constructor. + (Fragment::complete): Remove in favor of new constructor. + (Fragment::unexpanded): Remove as that Fragment type is no longer used + or possible. + (Fragment::get_tokens): Add helper to access a fragment's tokens. + * ast/rust-ast-fragment.h (enum class): Remove `FragmentKind::Unused` + * ast/rust-ast.cc (MacroInvocation::as_string): Display + builtin macro invocations properly. + * ast/rust-ast.h: Fix `DelimTokenTree` class copy constructors and + handling of its token vector. + * ast/rust-macro.h (class MacroMatcher): Format. + (class MetaItemSeq): Likewise. + (builtin_macro_from_string): Get a `BuiltinMacroKind` from a given + string, i.e the name of the macro (`assert!`, `cfg!` and so on). + * expand/rust-attribute-visitor.cc (AttrVisitor::visit): Do not expand + macros recursively anymore. + (AttrVisitor::maybe_expand_expr): Likewise. + (AttrVisitor::maybe_expand_type): Likewise. + * expand/rust-attribute-visitor.h: Likewise, and remove + `expand_macro_fragment_recursively` function. + * expand/rust-macro-builtins.cc (make_token): Add shorthand for + returning `std::unique_ptr<AST::Token>`s. + (make_macro_invocation): Add shorthand for returning fragments + containing builtin macro invocations. + (try_expand_macro_expression): Do not expand macros recursively. + (try_expand_single_string_literal): Likewise. + (try_expand_many_expr): Likewise. + (parse_single_string_literal): Error out more appropriately. + (MacroBuiltin::compile_error_handler): Add explanation for eager + invocation + (MacroBuiltin::file_handler): Return the proper tokens associated with + macro invocation, and builtin macros in the case of necessary eager + expansion. + (MacroBuiltin::column_handler): Likewise. + (MacroBuiltin::include_bytes_handler): Likewise. + (MacroBuiltin::include_str_handler): Likewise. + (MacroBuiltin::concat_handler): Likewise. + (MacroBuiltin::env_handler): Likewise. + (MacroBuiltin::cfg_handler): Likewise. + (MacroBuiltin::include_handler): Likewise. + (MacroBuiltin::line_handler): Likewise. + * expand/rust-macro-expand.cc (MacroExpander::expand_eager_invocations): + Add function to expand eager invocations *once* in the fixed point + pipeline. + (MacroExpander::expand_invoc): Call into `expand_eager_invocations` for + builtin macro invocations. + (MacroExpander::expand_crate): Use new `AttrVisitor` API. + (parse_many): Return tokens in `AST::Fragment`. + (transcribe_expression): Likewise. + (transcribe_type): Likewise. + * expand/rust-macro-expand.h (struct MacroExpander): Add `has_changed` + flag for fixed point checking. + * resolve/rust-early-name-resolver.cc (EarlyNameResolver::EarlyNameResolver): + Keep track of the current macro scope. + (EarlyNameResolver::go): Use `scoped` API. + (EarlyNameResolver::visit): Likewise. + * resolve/rust-early-name-resolver.h: Add `scoped` API. + * rust-session-manager.cc (Session::expansion): Perform macro expansion + in a fixed-point fashion. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-invoc-lexer.cc (MacroInvocLexer::get_token_slice): + Add API to retrieve token slices when lexing macro expansions. + * expand/rust-macro-invoc-lexer.h: Declare `get_token_slice`. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse.h: Move `parse_macro_invocation` to public API. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-item.h (class BlockExpr): Remove forward declaration of + class `BlockExpr`. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/tree/rust-hir-pattern.h + (TuplePatternItemsRanged::get_lower_patterns): Add method. + (TuplePatternItemsRanged::get_upper_patterns): Add method. + * backend/rust-compile-pattern.cc + (CompilePatternLet::visit): Implement TuplePattern visitor. + * backend/rust-compile-pattern.h + (CompilePatternLet::visit): Move TuplePattern visitor out of header file. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-unify.cc (UnifyRules::go): ensure the bounds are checked + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): remove error message + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.h: add const infterface + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::get_generic_param): make const + (SubstitutionRef::monomorphize): fix issue + * typecheck/rust-tyty-subst.h: constify interface + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * util/rust-lang-item.h: + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc (SubstitutionArg::is_conrete): fix check + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: update names + * backend/rust-compile-expr.cc (CompileExpr::resolve_method_address): + update to use new interface + * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_borrowed_pointer): likewise + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::unify_site): likewise + * typecheck/rust-tyty.cc (BaseType::destructure): likewise + (InferType::unify): removed old unify interface + (ErrorType::unify): likewise + (ADTType::unify): likewise + (TupleType::unify): likewise + (FnType::unify): likewise + (FnPtr::unify): likewise + (ClosureType::unify): likewise + (ArrayType::unify): likewise + (SliceType::unify): likewise + (BoolType::unify): likewise + (IntType::unify): likewise + (UintType::unify): likewise + (FloatType::unify): likewise + (USizeType::unify): likewise + (ISizeType::unify): likewise + (CharType::unify): likewise + (ReferenceType::unify): likewise + (PointerType::unify): likewise + (ParamType::unify): likewise + (StrType::unify): likewise + (NeverType::unify): likewise + (PlaceholderType::unify): likewise + (ProjectionType::unify): likewise + (DynamicObjectType::unify): likewise + * typecheck/rust-tyty.h: update destructure interface + * typecheck/rust-tyty-rules.h: Removed. + * typecheck/rust-unify.cc: New file. + * typecheck/rust-unify.h: New file. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.h: change interface to return self + * typecheck/rust-hir-trait-resolve.cc: likewise + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_segments): likewise + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): remove monomorphization hack + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc: add missing callback + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc: update copy constructors + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-bounds.cc: refactor to take a reference + * typecheck/rust-tyty-subst.cc: likewise + (SubstitutionRef::get_substitution_arguments): likewise + (SubstitutionRef::infer_substitions): likewise + * typecheck/rust-tyty-subst.h: likewise + * typecheck/rust-tyty.cc (ADTType::handle_substitions): likewise + (TupleType::handle_substitions): likewise + (FnType::handle_substitions): likewise + (ClosureType::handle_substitions): likewise + (ArrayType::handle_substitions): likewise + (SliceType::handle_substitions): likewise + (ReferenceType::handle_substitions): likewise + (PointerType::handle_substitions): likewise + (ParamType::handle_substitions): likewise + (ProjectionType::handle_substitions): likewise + * typecheck/rust-tyty.h: likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-ref.h: Moved to... + * typecheck/rust-hir-trait-reference.h: ...here. + * typecheck/rust-hir-trait-resolve.cc: refactor + * typecheck/rust-hir-trait-resolve.h (RUST_HIR_TRAIT_RESOLVE_H): likewise + * typecheck/rust-hir-type-check.h: likewise + * typecheck/rust-tyty.cc: likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: update name + * typecheck/rust-tyctx.cc: Moved to... + * typecheck/rust-typecheck-context.cc: ...here. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check.h: refactor + * typecheck/rust-tyctx.cc (TypeCheckContext::iterate): refactor + (TypeCheckContext::have_loop_context): likewise + (TypeCheckContext::push_new_loop_context): likewise + (TypeCheckContext::push_new_while_loop_context): likewise + (TypeCheckContext::peek_loop_context): likewise + (TypeCheckContext::pop_loop_context): likewise + (TypeCheckContext::swap_head_loop_context): likewise + (TypeCheckContext::insert_trait_reference): likewise + (TypeCheckContext::lookup_trait_reference): likewise + (TypeCheckContext::insert_receiver): likewise + (TypeCheckContext::lookup_receiver): likewise + (TypeCheckContext::insert_associated_type_mapping): likewise + (TypeCheckContext::clear_associated_type_mapping): likewise + (TypeCheckContext::lookup_associated_type_mapping): likewise + (TypeCheckContext::insert_variant_definition): likewise + (TypeCheckContext::lookup_variant_definition): likewise + (TypeCheckContext::insert_operator_overload): likewise + (TypeCheckContext::lookup_operator_overload): likewise + (TypeCheckContext::insert_unconstrained_check_marker): likewise + (TypeCheckContext::have_checked_for_unconstrained): likewise + (TypeCheckContext::insert_resolved_predicate): likewise + (TypeCheckContext::lookup_predicate): likewise + (TypeCheckContext::insert_query): likewise + (TypeCheckContext::query_completed): likewise + (TypeCheckContext::query_in_progress): likewise + (TypeCheckContext::insert_trait_query): likewise + (TypeCheckContext::trait_query_completed): likewise + (TypeCheckContext::trait_query_in_progress): likewise + (TypeCheckContextItem::Item::Item): likewise + (TypeCheckContextItem::TypeCheckContextItem): likewise + (TypeCheckContextItem::get_item): likewise + (TypeCheckContextItem::get_impl_item): likewise + (TypeCheckContextItem::get_trait_item): likewise + (TypeCheckContextItem::get_type): likewise + * typecheck/rust-tyty.cc (StructFieldType::StructFieldType): likewise + (StructFieldType::get_ref): likewise + (StructFieldType::get_name): likewise + (StructFieldType::get_field_type): likewise + (StructFieldType::set_field_type): likewise + (StructFieldType::is_concrete): likewise + (StructFieldType::debug): likewise + (StructFieldType::get_locus): likewise + (VariantDef::variant_type_string): likewise + (VariantDef::VariantDef): likewise + (VariantDef::operator=): likewise + (VariantDef::get_error_node): likewise + (VariantDef::is_error): likewise + (VariantDef::get_id): likewise + (VariantDef::get_defid): likewise + (VariantDef::get_variant_type): likewise + (VariantDef::is_data_variant): likewise + (VariantDef::is_dataless_variant): likewise + (VariantDef::get_identifier): likewise + (VariantDef::num_fields): likewise + (VariantDef::get_field_at_index): likewise + (VariantDef::get_fields): likewise + (VariantDef::lookup_field): likewise + (VariantDef::get_discriminant): likewise + (VariantDef::as_string): likewise + (VariantDef::is_equal): likewise + (VariantDef::clone): likewise + (VariantDef::monomorphized_clone): likewise + (VariantDef::get_ident): likewise + (TupleType::TupleType): likewise + (TupleType::get_unit_type): likewise + (TupleType::is_unit): likewise + (TupleType::num_fields): likewise + (TupleType::is_concrete): likewise + (TupleType::get_fields): likewise + (BoolType::BoolType): likewise + (BoolType::get_name): likewise + (BoolType::is_concrete): likewise + (IntType::IntType): likewise + (IntType::get_name): likewise + (IntType::get_int_kind): likewise + (IntType::is_concrete): likewise + (UintType::UintType): likewise + (UintType::get_name): likewise + (UintType::get_uint_kind): likewise + (UintType::is_concrete): likewise + (FloatType::FloatType): likewise + (FloatType::get_name): likewise + (FloatType::get_float_kind): likewise + (FloatType::is_concrete): likewise + (USizeType::USizeType): likewise + (USizeType::get_name): likewise + (USizeType::is_concrete): likewise + (ISizeType::ISizeType): likewise + (ISizeType::get_name): likewise + (ISizeType::is_concrete): likewise + (CharType::CharType): likewise + (CharType::is_concrete): likewise + (CharType::get_name): likewise + (ReferenceType::ReferenceType): likewise + (ReferenceType::is_concrete): likewise + (ReferenceType::mutability): likewise + (ReferenceType::is_mutable): likewise + (ReferenceType::is_dyn_object): likewise + (ReferenceType::is_dyn_slice_type): likewise + (ReferenceType::is_dyn_str_type): likewise + (PointerType::PointerType): likewise + (PointerType::is_concrete): likewise + (PointerType::mutability): likewise + (PointerType::is_mutable): likewise + (PointerType::is_const): likewise + (PointerType::is_dyn_object): likewise + (PointerType::is_dyn_slice_type): likewise + (PointerType::is_dyn_str_type): likewise + (ParamType::ParamType): likewise + (ParamType::get_generic_param): likewise + (ParamType::can_resolve): likewise + (ParamType::is_concrete): likewise + (StrType::StrType): likewise + (StrType::get_name): likewise + (StrType::is_concrete): likewise + (NeverType::NeverType): likewise + (NeverType::get_name): likewise + (NeverType::is_unit): likewise + (NeverType::is_concrete): likewise + (PlaceholderType::PlaceholderType): likewise + (PlaceholderType::get_name): likewise + (PlaceholderType::is_unit): likewise + (PlaceholderType::get_symbol): likewise + (PlaceholderType::is_concrete): likewise + (ProjectionType::is_unit): likewise + (ProjectionType::get_name): likewise + (ProjectionType::needs_generic_substitutions): likewise + (ProjectionType::supports_substitutions): likewise + (ProjectionType::has_subsititions_defined): likewise + (ProjectionType::get): likewise + (ProjectionType::is_concrete): likewise + (DynamicObjectType::is_concrete): likewise + * typecheck/rust-tyty.h: likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-path-probe.cc (PathProbeCandidate::Candidate::Candidate): refactor + (PathProbeCandidate::PathProbeCandidate): likewise + (PathProbeCandidate::as_string): likewise + (PathProbeCandidate::is_enum_candidate): likewise + (PathProbeCandidate::is_impl_candidate): likewise + (PathProbeCandidate::is_trait_candidate): likewise + (PathProbeCandidate::is_full_trait_item_candidate): likewise + (PathProbeCandidate::get_error): likewise + (PathProbeCandidate::is_error): likewise + (PathProbeCandidate::get_defid): likewise + (PathProbeCandidate::operator<): likewise + * typecheck/rust-hir-path-probe.h (struct PathProbeCandidate): likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-path-probe.cc (PathProbeType::PathProbeType): refactor + (PathProbeType::Probe): likewise + (PathProbeType::visit): likewise + (PathProbeType::process_enum_item_for_candiates): likewise + (PathProbeType::process_impl_items_for_candidates): likewise + (PathProbeType::is_reciever_generic): likewise + (PathProbeImplTrait::PathProbeImplTrait): likewise + (PathProbeImplTrait::Probe): likewise + (PathProbeImplTrait::process_trait_impl_items_for_candidates): likewise + * typecheck/rust-hir-path-probe.h (struct PathProbeCandidate): likewise + * typecheck/rust-hir-trait-resolve.cc + (PathProbeImplTrait::process_trait_impl_items_for_candidates): likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty.cc (BaseType::BaseType): refactor + (BaseType::~BaseType): likewise + (BaseType::get_ref): likewise + (BaseType::set_ref): likewise + (BaseType::get_ty_ref): likewise + (BaseType::set_ty_ref): likewise + (BaseType::is_equal): likewise + (BaseType::is_unit): likewise + (BaseType::get_kind): likewise + (BaseType::get_combined_refs): likewise + (BaseType::append_reference): likewise + (BaseType::supports_substitutions): likewise + (BaseType::has_subsititions_defined): likewise + (BaseType::can_substitute): likewise + (BaseType::needs_generic_substitutions): likewise + (BaseType::contains_type_parameters): likewise + (BaseType::get_ident): likewise + (BaseType::get_locus): likewise + (InferType::InferType): likewise + (InferType::get_infer_kind): likewise + (InferType::get_name): likewise + (InferType::is_concrete): likewise + (ErrorType::ErrorType): likewise + (ErrorType::is_unit): likewise + (ErrorType::is_concrete): likewise + (ErrorType::get_name): likewise + (ErrorType::monomorphized_clone): likewise + * typecheck/rust-tyty.h (class SubstitutionArgumentMappings): likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-substitution-mapper.cc (SubstMapper::SubstMapper): refactor + (SubstMapper::Resolve): likewise + (SubstMapper::InferSubst): likewise + (SubstMapper::have_generic_args): likewise + (SubstMapper::visit): likewise + (SubstMapperInternal::visit): likewise + (SubstMapperFromExisting::SubstMapperFromExisting): likewise + (SubstMapperFromExisting::Resolve): likewise + (SubstMapperFromExisting::visit): likewise + (GetUsedSubstArgs::GetUsedSubstArgs): likewise + (GetUsedSubstArgs::From): likewise + (GetUsedSubstArgs::visit): likewise + * typecheck/rust-substitution-mapper.h: refactor + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::get_generic_param): likewise + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: update the makefile + * typecheck/rust-tyty.cc (SubstitutionParamMapping::need_substitution): likewise + (SubstitutionParamMapping::override_context): likewise + (SubstitutionRef::get_mappings_from_generic_args): likewise + (SubstitutionRef::infer_substitions): likewise + (SubstitutionRef::are_mappings_bound): likewise + (SubstitutionRef::solve_missing_mappings_from_this): likewise + (SubstitutionRef::monomorphize): likewise + * typecheck/rust-tyty.h (class SubstitutionParamMapping): likewise + (class SubstitutionArg): likewise + (std::function<void): likewise + (class SubstitutionArgumentMappings): likewise + (class SubstitutionRef): likewise + * typecheck/rust-tyty-subst.cc: New file. + * typecheck/rust-tyty-subst.h: New file. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: update makefile + * typecheck/rust-tyty.cc (TyVar::TyVar): move to new file + (TyVar::get_tyty): likewise + (TyVar::get_implicit_infer_var): likewise + (TyVar::subst_covariant_var): likewise + (TyVar::clone): likewise + (TyVar::monomorphized_clone): likewise + (TyWithLocation::TyWithLocation): likewise + * typecheck/rust-tyty.h (class BaseType): cleanup + (class TypeBoundPredicate): move to its own file + (class TypeBoundPredicateItem): likewise + (class TypeBoundsMappings): likewise + (class TyVar): likewise + (class TyWithLocation): likewise + * typecheck/rust-tyty-bounds.h: New file. + * typecheck/rust-tyty-util.cc: New file. + * typecheck/rust-tyty-util.h: New file. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-bounds.cc (TypeBoundPredicateItem::error): refactor + (TypeBoundPredicateItem::is_error): likewise + (TypeBoundPredicateItem::get_parent): likewise + * typecheck/rust-tyty.h: Move the implementation for the above + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Removed copy-pasted comment. + +2023-04-06 mxlol233 <mxlol233@outlook.com> + + * Make-lang.in: Add object files: `rust-feature.o` and `rust-feature-gate.o` + * checks/errors/rust-feature-gate.cc: New file. + * checks/errors/rust-feature-gate.h: New file. + * checks/errors/rust-feature.cc: New file. + * checks/errors/rust-feature.h: New file. + * rust-session-manager.cc: Add FeatureGate check. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_closure_expr): Advance tokens + properly when parsing closure param list. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_generic_arg): Handle type + paths and nested generics properly. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-pattern.h: + (ReferencePattern::is_double_reference): Add method. + (ReferencePattern::get_is_mut): Add method. + * hir/rust-ast-lower-pattern.cc + (ASTLoweringPattern::visit): Add ReferencePattern visitor. + * hir/rust-ast-lower-pattern.h: + (ASTLoweringPattern::visit): Add ReferencePattern visitor. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/tree/rust-hir-pattern.h + (class ReferencePattern): Remove has_two_amps field. + * hir/tree/rust-hir-full-test.cc + (ReferencePattern::as_string): Remove usage of ReferencePattern::has_two_amps. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-fnparam.h + (CompileFnParam::visit): Remove HIR::GroupedPattern visitor. + * backend/rust-compile-pattern.cc + (CompilePatternCaseLabelExpr::visit): Remove HIR::GroupedPattern visitor. + (CompilePatternBindings::visit): Remove HIR::GroupedPattern visitor. + * backend/rust-compile-pattern.h + (CompilePatternCaseLabelExpr::visit): Remove HIR::GroupedPattern visitor. + (CompilePatternBindings::visit): Remove HIR::GroupedPattern visitor. + (CompilePatternLet::visit): Remove HIR::GroupedPattern visitor. + * backend/rust-compile-resolve-path.h + (ResolvePathRef::visit): Remove HIR::GroupedPattern visitor. + * backend/rust-compile-var-decl.h + (CompileVarDecl::visit): Remove HIR::GroupedPattern visitor. + * checks/errors/rust-const-checker.cc + (ConstChecker::visit): Remove HIR::GroupedPattern visitor. + * checks/errors/rust-const-checker.h + (ConstChecker::visit): Remove HIR::GroupedPattern visitor. + * checks/errors/rust-unsafe-checker.cc + (UnsafeChecker::visit): Remove HIR::GroupedPattern visitor. + * checks/errors/rust-unsafe-checker.h + (UnsafeChecker::visit): Remove HIR::GroupedPattern visitor. + * hir/rust-hir-dump.cc (Dump::visit): Remove HIR::GroupedPattern visitor. + * hir/rust-hir-dump.h (Dump::visit): Remove HIR::GroupedPattern visitor. + * hir/tree/rust-hir-full-decls.h (class GroupedPattern): Remove class. + * hir/tree/rust-hir-full-test.cc (GroupedPattern::accept_vis): Remove method. + * hir/tree/rust-hir-pattern.h (class GroupedPattern): Remove class. + * hir/tree/rust-hir-visitor.h + (HIRFullVisitor::visit): Remove HIR::GroupedPattern visitor. + (HIRFullVisitorBase::visit): Remove HIR::GroupedPattern visitor. + (HIRPatternVisitor::visit): Remove HIR::GroupedPattern visitor. + * typecheck/rust-hir-type-check-pattern.cc + (TypeCheckPattern::visit): Remove HIR::GroupedPattern visitor. + * typecheck/rust-hir-type-check-pattern.h + (TypeCheckPattern::visit): Remove HIR::GroupedPattern visitor. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/rust-ast-lower-pattern.cc + (ASTLoweringPattern::visit): Lower AST::GroupedPattern to its inner pattern. + +2023-04-06 MAHAD <mahadtxt@gmail.com> + + * rust-buffered-queue.h: Moved to... + * util/rust-buffered-queue.h: ...here. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_type): Handle double ampersan + properly + (Parser::parse_reference_type): Call into `parse_reference_type_inner` + and wrap double reference types in another `AST::ReferenceType` node + (Parser::parse_reference_type_inner): Add parsing implementation + which does not care about the leading token (& or &&) + (Parser::parse_type_no_bounds): Handle double ampersand properly + * parse/rust-parse.h: Declare `parse_reference_type_inner` + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-pattern.cc (CompilePatternLet::visit): New function. + * backend/rust-compile-stmt.cc (CompileStmt::visit): Likewise. + * backend/rust-compile-pattern.h (class CompilePatternLet): New visitor. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-macro.h (enum class): Add `BuiltinMacro` enum class. + * expand/rust-attribute-visitor.cc (AttrVisitor::visit): Mention + switching on `macro.kind` once builtin macro invocations are properly + handled. + * parse/rust-parse-impl.h (Parser::parse_macro_invocation): Switch to new MacroInvocation + API. + (Parser::parse_type): Likewise. + (Parser::parse_type_no_bounds): Likewise. + +2023-04-06 Abdul Rafey <abdulrafeyq@gmail.com> + + * ast/rust-ast-dump.cc (Dump::visit): removed extra indentations in trait ast dump + +2023-04-06 Abdul Rafey <abdulrafeyq@gmail.com> + + * parse/rust-parse-impl.h (Parser::null_denotation): Add proper error + when seeing wildcard var on right side of assignment. + +2023-04-06 Abdul Rafey <abdulrafeyq@gmail.com> + + * ast/rust-ast.cc: Fix include list. + * ast/rust-expr.h: Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + * rust-backend.h: Likewise. + * util/rust-lang-item.h: Likewise. + * operator.h: Moved to... + * util/rust-operators.h: ...here. + +2023-04-06 Parthib <parthibdutta02@gmail.com> + + * Make-lang.in: Rename object file. + * ast/rust-ast-full-test.cc: Moved to... + * ast/rust-ast.cc: ...here. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-pattern.cc (CompilePatternCaseLabelExpr::visit): Add proper + visitor. + (CompilePatternBindings::visit): Likewise. + * backend/rust-compile-pattern.h: Declare them. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): Add proper + visitor. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/tree/rust-hir-pattern.h: Add get_item method. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/rust-ast-lower-pattern.cc (ASTLoweringPattern::visit): Add proper visitor. + * hir/rust-ast-lower-pattern.h: Declare it. + +2023-04-06 Lyra <teromene@teromene.fr> + + * expand/rust-macro-expand.cc (transcribe_expression): Fix ICE when expanding + empty macros. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-pattern.h: Support GroupedPattern properly. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::compile_locals_for_block): + Allow patterns to declare zero or multiple variables. + * backend/rust-compile-var-decl.h: Change function declaration. + +2023-04-06 mxlol233 <mxlol233@outlook.com> + + * lex/rust-lex.cc (Lexer::build_token): Make location enclose entire token. + (Lexer::parse_byte_char): Likewise. + (Lexer::parse_byte_string): Likewise. + (Lexer::parse_raw_byte_string): Likewise. + (Lexer::parse_raw_identifier): Likewise. + (Lexer::parse_string): Likewise. + (Lexer::parse_identifier_or_keyword): Likewise. + (Lexer::parse_raw_string): Likewise. + (Lexer::parse_non_decimal_int_literal): Likewise. + (Lexer::parse_decimal_int_or_float): Likewise. + (Lexer::parse_char_or_lifetime): Likewise. + +2023-04-06 mxlol233 <mxlol233@outlook.com> + + * ast/rust-ast.h: Add get_locus method. + * ast/rust-expr.h: Likewise. + * ast/rust-macro.h: Likewise. + +2023-04-06 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-stmt.cc (TypeCheckStmt::visit): Cleanup LetStmt + type checking. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * hir/tree/rust-hir-path.h: Add const get_identifier and get_type method. + * typecheck/rust-hir-path-probe.h: Use new SubstitutionArgumentMappings constructor. + * typecheck/rust-hir-trait-resolve.cc: Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + * typecheck/rust-tyty-bounds.cc (TypeCheckBase::get_predicate_from_bound): + Do not assert failure on size mismatch anymore. + (TypeBoundPredicate::TypeBoundPredicate): Use new SubstitutionArgumentMappings constructor. + (TypeBoundPredicate::operator=): Likewise. + (TypeBoundPredicate::apply_generic_arguments): Likewise. + (TypeBoundPredicateItem::get_tyty_for_receiver): Likewise. + (TypeBoundPredicate::get_num_associated_bindings): Likewise. + (TypeBoundPredicate::lookup_associated_type): Fix implementation for new system. + (TypeBoundPredicate::get_associated_type_items): Likewise. + * typecheck/rust-tyty.cc (SubstitutionRef::get_mappings_from_generic_args): Add new + behavior. + (SubstitutionRef::infer_substitions): Use new constructor and add comment. + (SubstitutionRef::solve_missing_mappings_from_this): Use new constructor. + * typecheck/rust-tyty.h: Define new constructors. + +2023-04-06 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-type.cc (ResolveGenericArgs::go): Add name resolution to + Trait items. + +2023-04-06 Raiki Tamura <tamaron1203@gmail.com> + + * ast/rust-ast-full-decls.h (class MacroItem): Remove forward declaration. + * ast/rust-ast-full-test.cc (MacroRulesDefinition): + Rework MacroRulesDefinition class + * ast/rust-ast.h (class MacroItem): Remove abstract class. + * ast/rust-item.h (class MacroItem): Remove forward declaration. + * ast/rust-macro.h (class MacroItem): Likewise. + (class MacroRulesDefinition): Add MacroKind enum. + (class MacroInvocation): Fix inheritance. + * lex/rust-token.h: Token "macro" is now used. + * parse/rust-parse-impl.h (Parser::parse_item): Add handling for MACRO. + (Parser::parse_vis_item): Call into parse_decl_macro_def. + (Parser::parse_macro_item): Delete function. + (Parser::parse_macro_rules_def): Return MBE macros only. + (Parser::parse_decl_macro_def): New function. + (Parser::parse_stmt): Handle MACRO token. + (Parser::parse_stmt_or_expr_without_block): Call into parse_macro_rules_def. + * parse/rust-parse.h: Declare new function. + +2023-04-06 mxlol233 <mxlol233@outlook.com> + + * parse/rust-parse-impl.h (Parser::parse_generic_arg): Add proper bound parsing. + +2023-04-06 Dave <dme2223@gmail.com> + + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Use StackedContext + class. + +2023-04-06 Prajwal S N <prajwalnadig21@gmail.com> + + * checks/errors/rust-unsafe-checker.cc (check_target_attr): New function. + (UnsafeChecker::check_function_attr): Call into `check_target_attr`. + (UnsafeChecker::visit): Check for target_feature attributes. + * checks/errors/rust-unsafe-checker.h: Add declarations. + * util/rust-attributes.cc: Add attribute. + +2023-04-06 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Fix typo. + 2023-02-22 Thomas Schwinge <thomas@codesourcery.com> * rust-lang.cc (grs_langhook_type_for_mode): Also consider all diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index dddc70a..3ed0c09 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -73,7 +73,7 @@ GRS_OBJS = \ rust/rust-lex.o \ rust/rust-cfg-parser.o \ rust/rust-parse.o \ - rust/rust-ast-full-test.o \ + rust/rust-ast.o \ rust/rust-ast-fragment.o \ rust/rust-ast-dump.o \ rust/rust-hir-dump.o \ @@ -86,10 +86,11 @@ GRS_OBJS = \ rust/rust-macro-invoc-lexer.o \ rust/rust-macro-substitute-ctx.o \ rust/rust-macro-builtins.o \ - rust/rust-hir-full-test.o \ + rust/rust-hir.o \ rust/rust-hir-map.o \ rust/rust-attributes.o \ rust/rust-abi.o \ + rust/rust-macro.o \ rust/rust-ast-lower.o \ rust/rust-ast-lower-base.o \ rust/rust-ast-lower-pattern.o \ @@ -115,11 +116,14 @@ GRS_OBJS = \ rust/rust-pub-restricted-visitor.o \ rust/rust-privacy-reporter.o \ rust/rust-tyty.o \ + rust/rust-tyty-util.o \ rust/rust-tyty-call.o \ - rust/rust-tyctx.o \ + rust/rust-tyty-subst.o \ + rust/rust-typecheck-context.o \ rust/rust-tyty-bounds.o \ rust/rust-hir-type-check-util.o \ rust/rust-hir-trait-resolve.o \ + rust/rust-hir-trait-reference.o \ rust/rust-hir-type-check-item.o \ rust/rust-hir-type-check-type.o \ rust/rust-hir-type-check-struct.o \ @@ -130,8 +134,10 @@ GRS_OBJS = \ rust/rust-hir-type-check-implitem.o \ rust/rust-hir-dot-operator.o \ rust/rust-hir-path-probe.o \ + rust/rust-type-util.o \ rust/rust-coercion.o \ rust/rust-casts.o \ + rust/rust-unify.o \ rust/rust-hir-type-check-base.o \ rust/rust-autoderef.o \ rust/rust-substitution-mapper.o \ @@ -161,6 +167,8 @@ GRS_OBJS = \ rust/rust-import-archive.o \ rust/rust-extern-crate.o \ rust/rust-builtins.o \ + rust/rust-feature.o \ + rust/rust-feature-gate.o \ $(END) # removed object files from here diff --git a/gcc/rust/ast/rust-ast-dump.cc b/gcc/rust/ast/rust-ast-dump.cc index 77e04b9..10fb313 100644 --- a/gcc/rust/ast/rust-ast-dump.cc +++ b/gcc/rust/ast/rust-ast-dump.cc @@ -1072,8 +1072,6 @@ Dump::visit (TypeBoundWhereClauseItem &item) void Dump::visit (Method &method) { - // FIXME: Do we really need to dump the indentation here? - stream << indentation; visit (method.get_visibility ()); stream << "fn " << method.get_method_name () << '('; @@ -1326,7 +1324,7 @@ void Dump::visit (TraitItemFunc &item) { auto func = item.get_trait_function_decl (); - stream << indentation << "fn " << func.get_identifier () << '('; + stream << "fn " << func.get_identifier () << '('; visit_items_joined_by_separator (func.get_function_params ()); @@ -1340,9 +1338,6 @@ Dump::visit (TraitItemMethod &item) { auto method = item.get_trait_method_decl (); - // FIXME: Do we really need to dump the indentation here? - stream << indentation; - // FIXME: Can we have visibility here? // emit_visibility (method.get_visibility ()); stream << "fn " << method.get_identifier () << '('; @@ -1683,6 +1678,10 @@ void Dump::visit (SlicePattern &) {} +void +Dump::visit (AltPattern &) +{} + // rust-stmt.h void Dump::visit (EmptyStmt &) diff --git a/gcc/rust/ast/rust-ast-dump.h b/gcc/rust/ast/rust-ast-dump.h index 56918f5..dfe6db0 100644 --- a/gcc/rust/ast/rust-ast-dump.h +++ b/gcc/rust/ast/rust-ast-dump.h @@ -293,6 +293,7 @@ private: void visit (TuplePattern &pattern); void visit (GroupedPattern &pattern); void visit (SlicePattern &pattern); + void visit (AltPattern &pattern); // rust-stmt.h void visit (EmptyStmt &stmt); diff --git a/gcc/rust/ast/rust-ast-fragment.cc b/gcc/rust/ast/rust-ast-fragment.cc index c491609..a9dc474 100644 --- a/gcc/rust/ast/rust-ast-fragment.cc +++ b/gcc/rust/ast/rust-ast-fragment.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. @@ -21,8 +21,9 @@ namespace Rust { namespace AST { -Fragment::Fragment (FragmentKind kind, std::vector<SingleASTNode> nodes) - : kind (kind), nodes (std::move (nodes)) +Fragment::Fragment (FragmentKind kind, std::vector<SingleASTNode> nodes, + std::vector<std::unique_ptr<AST::Token>> tokens) + : kind (kind), nodes (std::move (nodes)), tokens (std::move (tokens)) {} Fragment::Fragment (Fragment const &other) : kind (other.get_kind ()) @@ -33,13 +34,17 @@ Fragment::Fragment (Fragment const &other) : kind (other.get_kind ()) Fragment & Fragment::operator= (Fragment const &other) { + kind = other.get_kind (); + nodes.clear (); nodes.reserve (other.nodes.size ()); - kind = other.get_kind (); for (auto &n : other.nodes) - { - nodes.push_back (n); - } + nodes.push_back (n); + + tokens.clear (); + tokens.reserve (other.tokens.size ()); + for (auto &t : other.tokens) + tokens.emplace_back (t->clone_token ()); return *this; } @@ -47,19 +52,20 @@ Fragment::operator= (Fragment const &other) Fragment Fragment::create_error () { - return Fragment (FragmentKind::Error, {}); + return Fragment (FragmentKind::Error, {}, {}); } -Fragment -Fragment::complete (std::vector<AST::SingleASTNode> nodes) -{ - return Fragment (FragmentKind::Complete, std::move (nodes)); -} +Fragment::Fragment (std::vector<AST::SingleASTNode> nodes, + std::vector<std::unique_ptr<AST::Token>> tokens) + : kind (FragmentKind::Complete), nodes (std::move (nodes)), + tokens (std::move (tokens)) +{} -Fragment -Fragment::unexpanded () +Fragment::Fragment (std::vector<AST::SingleASTNode> nodes, + std::unique_ptr<AST::Token> token) + : kind (FragmentKind::Complete), nodes (std::move (nodes)) { - return Fragment (FragmentKind::Unexpanded, {}); + tokens.emplace_back (std::move (token)); } std::vector<SingleASTNode> & @@ -68,6 +74,12 @@ Fragment::get_nodes () return nodes; } +std::vector<std::unique_ptr<AST::Token>> & +Fragment::get_tokens () +{ + return tokens; +} + FragmentKind Fragment::get_kind () const { diff --git a/gcc/rust/ast/rust-ast-fragment.h b/gcc/rust/ast/rust-ast-fragment.h index 3ef4ba1..41f5a28 100644 --- a/gcc/rust/ast/rust-ast-fragment.h +++ b/gcc/rust/ast/rust-ast-fragment.h @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. @@ -28,11 +28,6 @@ namespace AST { enum class FragmentKind { /** - * If an AST Fragment still contains unexpanded tokens - this should only be - * used in the case of builtin macros which need to be expanded eagerly. - */ - Unexpanded, - /** * A completely expanded AST Fragment. This signifies that all * `SingleASTNode`s in the `nodes` vector are valid. * @@ -68,15 +63,18 @@ public: /** * Create a complete AST fragment */ - static Fragment complete (std::vector<AST::SingleASTNode> nodes); + Fragment (std::vector<AST::SingleASTNode> nodes, + std::vector<std::unique_ptr<AST::Token>> tokens); /** - * Create a fragment which contains unexpanded nodes + * Create a complete AST fragment made of a single token */ - static Fragment unexpanded (); + Fragment (std::vector<AST::SingleASTNode> nodes, + std::unique_ptr<AST::Token> tok); FragmentKind get_kind () const; std::vector<SingleASTNode> &get_nodes (); + std::vector<std::unique_ptr<AST::Token>> &get_tokens (); bool is_error () const; bool should_expand () const; @@ -90,7 +88,8 @@ public: void accept_vis (ASTVisitor &vis); private: - Fragment (FragmentKind kind, std::vector<SingleASTNode> nodes); + Fragment (FragmentKind kind, std::vector<SingleASTNode> nodes, + std::vector<std::unique_ptr<AST::Token>> tokens); FragmentKind kind; @@ -105,6 +104,12 @@ private: std::vector<SingleASTNode> nodes; /** + * The tokens associated with an AST fragment. This vector represents the + * actual tokens of the various nodes that are part of the fragment. + */ + std::vector<std::unique_ptr<AST::Token>> tokens; + + /** * We need to make a special case for Expression and Type fragments as only * one Node will be extracted from the `nodes` vector */ diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index 136a25a..64341d3 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -51,7 +51,6 @@ class Lifetime; class GenericParam; class LifetimeParam; class ConstGenericParam; -class MacroItem; class TraitItem; class InherentImplItem; class TraitImplItem; @@ -150,6 +149,7 @@ struct MatchCase; class MatchExpr; class AwaitExpr; class AsyncBlockExpr; +class InlineAsm; // rust-stmt.h class EmptyStmt; @@ -250,6 +250,7 @@ class TuplePatternItemsRanged; class TuplePattern; class GroupedPattern; class SlicePattern; +class AltPattern; // rust-type.h class TraitBound; diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index aa59a11..1083e83 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -203,6 +203,7 @@ public: virtual void visit (TuplePattern &pattern) = 0; virtual void visit (GroupedPattern &pattern) = 0; virtual void visit (SlicePattern &pattern) = 0; + virtual void visit (AltPattern &pattern) = 0; // rust-stmt.h virtual void visit (EmptyStmt &stmt) = 0; diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast.cc index 4f593dc..68a7dfd 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "rust-session-manager.h" #include "rust-lex.h" #include "rust-parse.h" -#include "operator.h" +#include "rust-operators.h" /* Compilation unit used for various AST-related functions that would make * the headers too long if they were defined inline and don't receive any @@ -1284,6 +1284,7 @@ MacroRulesDefinition::as_string () const // get outer attrs str += append_attributes (outer_attrs, OUTER); + // TODO: deal with macro_2_0 str += "macro_rules!"; str += rule_name; @@ -1322,6 +1323,12 @@ std::string MacroInvocation::as_string () const { std::string str = "MacroInvocation: "; + auto is_builtin = kind == InvocKind::Builtin; + + if (is_builtin) + str += "[builtin] "; + else + str += "[regular] "; str += append_attributes (outer_attrs, OUTER); @@ -1330,6 +1337,16 @@ MacroInvocation::as_string () const str += "\n has semicolon: "; str += has_semicolon () ? "true" : "false"; + if (is_builtin) + { + str += "[PENDING EAGER INVOCATIONS]: "; + for (auto &pending : pending_eager_invocs) + { + str += pending->as_string (); + str += "\n"; + } + } + return str; } @@ -2688,6 +2705,17 @@ SlicePattern::as_string () const } std::string +AltPattern::as_string () const +{ + std::string str ("AltPattern: "); + + for (const auto &pattern : alts) + str += "\n " + pattern->as_string (); + + return str; +} + +std::string TuplePatternItemsMultiple::as_string () const { std::string str; @@ -4056,7 +4084,7 @@ Module::load_items () inner_attrs = parser.parse_inner_attributes (); auto parsed_items = parser.parse_items (); for (const auto &error : parser.get_errors ()) - error.emit_error (); + error.emit (); items = std::move (parsed_items); kind = ModuleKind::LOADED; @@ -5633,6 +5661,12 @@ SlicePattern::accept_vis (ASTVisitor &vis) } void +AltPattern::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void EmptyStmt::accept_vis (ASTVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index aa86f2f..585bdb0 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -630,6 +630,8 @@ public: virtual ~MetaItemInner (); + virtual Location get_locus () const = 0; + virtual std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; @@ -771,6 +773,7 @@ public: DelimTokenTree (DelimTokenTree const &other) : delim_type (other.delim_type), locus (other.locus) { + token_trees.clear (); token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) token_trees.push_back (e->clone_token_tree ()); @@ -782,6 +785,7 @@ public: delim_type = other.delim_type; locus = other.locus; + token_trees.clear (); token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) token_trees.push_back (e->clone_token_tree ()); @@ -1350,21 +1354,19 @@ protected: } }; -// A macro item AST node - abstract base class -class MacroItem : public Item -{ -}; - // Item used in trait declarations - abstract base class class TraitItem { protected: - TraitItem () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} + TraitItem (Location locus) + : node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus) + {} // Clone function implementation as pure virtual method virtual TraitItem *clone_trait_item_impl () const = 0; NodeId node_id; + Location locus; public: virtual ~TraitItem () {} @@ -1383,6 +1385,7 @@ public: virtual bool is_marked_for_strip () const = 0; NodeId get_node_id () const { return node_id; } + Location get_locus () const { return locus; } }; /* Abstract base class for items used within an inherent impl block (the impl @@ -1526,6 +1529,9 @@ public: DelimTokenTree &get_delim_tok_tree () { return token_tree; } const DelimTokenTree &get_delim_tok_tree () const { return token_tree; } + // Set the delim token tree of a macro invocation + void set_delim_tok_tree (DelimTokenTree tree) { token_tree = tree; } + // TODO: this mutable getter seems kinda dodgy SimplePath &get_path () { return path; } const SimplePath &get_path () const { return path; } diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index c58fae5..f546184 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -3,7 +3,7 @@ #include "rust-ast.h" #include "rust-path.h" -#include "operator.h" +#include "rust-operators.h" namespace Rust { namespace AST { @@ -150,6 +150,8 @@ public: std::string as_string () const override { return lit_expr.as_string (); } + Location get_locus () const override { return lit_expr.get_locus (); } + void accept_vis (ASTVisitor &vis) override; bool check_cfg_predicate (const Session &session) const override; @@ -178,6 +180,12 @@ public: return path.as_string () + " = " + lit.as_string (); } + // There are two Locations in MetaItemPathLit (path and lit_expr), + // we have no idea use which of them, just simply return UNKNOWN_LOCATION + // now. + // Maybe we will figure out when we really need the location in the future. + Location get_locus () const override { return Location (UNKNOWN_LOCATION); } + void accept_vis (ASTVisitor &vis) override; bool check_cfg_predicate (const Session &session) const override; @@ -4626,6 +4634,144 @@ protected: return new AsyncBlockExpr (*this); } }; + +// Inline Assembly Node +class InlineAsm : public ExprWithoutBlock +{ + // Inline-assembly specific options + enum InlineAsmOptions + { + PURE = 1 << 0, + NOMEM = 1 << 1, + READONLY = 1 << 2, + PRESERVES_FLAGS = 1 << 3, + NORETURN = 1 << 4, + NOSTACK = 1 << 5, + ATT_SYNTAX = 1 << 6, + RAW = 1 << 7, + MAY_UNWIND = 1 << 8, + }; + + struct AnonConst + { + NodeId id; + std::unique_ptr<Expr> value; + }; + + struct InlineAsmRegOrRegClass + { + enum Type + { + Reg, + RegClass, + }; + + struct Reg + { + std::string Symbol; + }; + + struct RegClass + { + std::string Symbol; + }; + + Identifier name; + Location locus; + }; + + struct InlineAsmOperand + { + enum RegisterType + { + In, + Out, + InOut, + SplitInOut, + Const, + Sym, + }; + + struct In + { + InlineAsmRegOrRegClass reg; + std::unique_ptr<Expr> expr; + }; + + struct Out + { + InlineAsmRegOrRegClass reg; + bool late; + std::unique_ptr<Expr> expr; // can be null + }; + + struct InOut + { + InlineAsmRegOrRegClass reg; + bool late; + std::unique_ptr<Expr> expr; // this can't be null + }; + + struct SplitInOut + { + InlineAsmRegOrRegClass reg; + bool late; + std::unique_ptr<Expr> in_expr; + std::unique_ptr<Expr> out_expr; // could be null + }; + + struct Const + { + AnonConst anon_const; + }; + + struct Sym + { + std::unique_ptr<Expr> sym; + }; + Location locus; + }; + + struct InlineAsmPlaceHolder + { + size_t operand_idx; + char modifier; // can be null + Location locus; + }; + + struct InlineAsmTemplatePiece + { + bool is_placeholder; + union + { + std::string string; + InlineAsmPlaceHolder placeholder; + }; + }; + + struct TupleClobber + { + // as gccrs still doesen't contain a symbol class I have put them as strings + std::string symbol; + Location loc; + }; + + struct TupleTemplateStr + { + // as gccrs still doesen't contain a symbol class I have put them as strings + std::string symbol; + std::string optional_symbol; + Location loc; + }; + +public: + std::vector<InlineAsmTemplatePiece> template_; + std::vector<TupleTemplateStr> template_strs; + std::vector<InlineAsmOperand> operands; + TupleClobber clobber_abi; + InlineAsmOptions options; + std::vector<Location> line_spans; +}; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 7ea7b86..1620961 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -22,11 +22,11 @@ #include "rust-ast.h" #include "rust-path.h" #include "rust-common.h" +#include "rust-expr.h" namespace Rust { namespace AST { // forward decls -class BlockExpr; class TypePath; // TODO: inline? @@ -2908,7 +2908,6 @@ class TraitItemFunc : public TraitItem std::vector<Attribute> outer_attrs; TraitFunctionDecl decl; std::unique_ptr<BlockExpr> block_expr; - Location locus; public: // Returns whether function has a definition or is just a declaration. @@ -2916,14 +2915,14 @@ public: TraitItemFunc (TraitFunctionDecl decl, std::unique_ptr<BlockExpr> block_expr, std::vector<Attribute> outer_attrs, Location locus) - : TraitItem (), outer_attrs (std::move (outer_attrs)), - decl (std::move (decl)), block_expr (std::move (block_expr)), - locus (locus) + : TraitItem (locus), outer_attrs (std::move (outer_attrs)), + decl (std::move (decl)), block_expr (std::move (block_expr)) {} // Copy constructor with clone TraitItemFunc (TraitItemFunc const &other) - : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) + : TraitItem (other.locus), outer_attrs (other.outer_attrs), + decl (other.decl) { node_id = other.node_id; @@ -2956,8 +2955,6 @@ public: std::string as_string () const override; - Location get_locus () const { return locus; } - void accept_vis (ASTVisitor &vis) override; // Invalid if trait decl is empty, so base stripping on that. @@ -3128,7 +3125,6 @@ class TraitItemMethod : public TraitItem std::vector<Attribute> outer_attrs; TraitMethodDecl decl; std::unique_ptr<BlockExpr> block_expr; - Location locus; public: // Returns whether method has a definition or is just a declaration. @@ -3136,14 +3132,14 @@ public: TraitItemMethod (TraitMethodDecl decl, std::unique_ptr<BlockExpr> block_expr, std::vector<Attribute> outer_attrs, Location locus) - : TraitItem (), outer_attrs (std::move (outer_attrs)), - decl (std::move (decl)), block_expr (std::move (block_expr)), - locus (locus) + : TraitItem (locus), outer_attrs (std::move (outer_attrs)), + decl (std::move (decl)), block_expr (std::move (block_expr)) {} // Copy constructor with clone TraitItemMethod (TraitItemMethod const &other) - : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) + : TraitItem (other.locus), outer_attrs (other.outer_attrs), + decl (other.decl) { node_id = other.node_id; @@ -3176,8 +3172,6 @@ public: std::string as_string () const override; - Location get_locus () const { return locus; } - void accept_vis (ASTVisitor &vis) override; // Invalid if trait decl is empty, so base stripping on that. @@ -3219,8 +3213,6 @@ class TraitItemConst : public TraitItem // bool has_expression; std::unique_ptr<Expr> expr; - Location locus; - public: // Whether the constant item has an associated expression. bool has_expression () const { return expr != nullptr; } @@ -3228,14 +3220,14 @@ public: TraitItemConst (Identifier name, std::unique_ptr<Type> type, std::unique_ptr<Expr> expr, std::vector<Attribute> outer_attrs, Location locus) - : TraitItem (), outer_attrs (std::move (outer_attrs)), - name (std::move (name)), type (std::move (type)), expr (std::move (expr)), - locus (locus) + : TraitItem (locus), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), type (std::move (type)), expr (std::move (expr)) {} // Copy constructor with clones TraitItemConst (TraitItemConst const &other) - : outer_attrs (other.outer_attrs), name (other.name), locus (other.locus) + : TraitItem (other.locus), outer_attrs (other.outer_attrs), + name (other.name) { node_id = other.node_id; @@ -3328,8 +3320,6 @@ class TraitItemType : public TraitItem std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; // inlined form - Location locus; - public: // Returns whether trait item type has type param bounds. bool has_type_param_bounds () const { return !type_param_bounds.empty (); } @@ -3337,14 +3327,14 @@ public: TraitItemType (Identifier name, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, std::vector<Attribute> outer_attrs, Location locus) - : TraitItem (), outer_attrs (std::move (outer_attrs)), - name (std::move (name)), - type_param_bounds (std::move (type_param_bounds)), locus (locus) + : TraitItem (locus), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), type_param_bounds (std::move (type_param_bounds)) {} // Copy constructor with vector clone TraitItemType (TraitItemType const &other) - : outer_attrs (other.outer_attrs), name (other.name), locus (other.locus) + : TraitItem (other.locus), outer_attrs (other.outer_attrs), + name (other.name) { node_id = other.node_id; type_param_bounds.reserve (other.type_param_bounds.size ()); @@ -3374,8 +3364,6 @@ public: std::string as_string () const override; - Location get_locus () const { return locus; } - void accept_vis (ASTVisitor &vis) override; // Invalid if name is empty, so base stripping on that. @@ -4391,8 +4379,6 @@ protected: } }; -// Replaced with forward decls - defined in "rust-macro.h" -class MacroItem; class MacroRulesDefinition; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-macro.cc b/gcc/rust/ast/rust-macro.cc new file mode 100644 index 0000000..b6f8f6c --- /dev/null +++ b/gcc/rust/ast/rust-macro.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-macro.h" + +namespace Rust { +namespace AST { + +BuiltinMacro +builtin_macro_from_string (const std::string &identifier) +{ + if (identifier == "assert") + return BuiltinMacro::Assert; + + if (identifier == "file") + return BuiltinMacro::File; + + if (identifier == "line") + return BuiltinMacro::Line; + + if (identifier == "column") + return BuiltinMacro::Column; + + if (identifier == "include_bytes") + return BuiltinMacro::IncludeBytes; + + if (identifier == "include_str") + return BuiltinMacro::IncludeStr; + + if (identifier == "compile_error") + return BuiltinMacro::CompileError; + + if (identifier == "concat") + return BuiltinMacro::Concat; + + if (identifier == "env") + return BuiltinMacro::Env; + + if (identifier == "cfg") + return BuiltinMacro::Cfg; + + if (identifier == "include") + return BuiltinMacro::Include; + + gcc_unreachable (); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index fc4b5b8..be8ed56 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -23,13 +23,11 @@ #include "rust-ast.h" #include "rust-ast-fragment.h" #include "rust-location.h" +#include "rust-item.h" +#include "rust-make-unique.h" namespace Rust { namespace AST { - -// Decls as definitions moved to rust-ast.h -class MacroItem; - class MacroFragSpec { public: @@ -224,7 +222,7 @@ public: }; private: - std::vector<std::unique_ptr<MacroMatch> > matches; + std::vector<std::unique_ptr<MacroMatch>> matches; MacroRepOp op; // bool has_sep; @@ -237,7 +235,7 @@ public: // Returns whether macro match repetition has separator token. bool has_sep () const { return sep != nullptr; } - MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch> > matches, + MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch>> matches, MacroRepOp op, std::unique_ptr<MacroRepSep> sep, Location locus) : matches (std::move (matches)), op (op), sep (std::move (sep)), @@ -292,8 +290,8 @@ public: MacroRepOp get_op () const { return op; } const std::unique_ptr<MacroRepSep> &get_sep () const { return sep; } - std::vector<std::unique_ptr<MacroMatch> > &get_matches () { return matches; } - const std::vector<std::unique_ptr<MacroMatch> > &get_matches () const + std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; } + const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const { return matches; } @@ -311,7 +309,7 @@ protected: class MacroMatcher : public MacroMatch { DelimType delim_type; - std::vector<std::unique_ptr<MacroMatch> > matches; + std::vector<std::unique_ptr<MacroMatch>> matches; Location locus; // TODO: think of way to mark invalid that doesn't take up more space @@ -319,7 +317,7 @@ class MacroMatcher : public MacroMatch public: MacroMatcher (DelimType delim_type, - std::vector<std::unique_ptr<MacroMatch> > matches, + std::vector<std::unique_ptr<MacroMatch>> matches, Location locus) : delim_type (delim_type), matches (std::move (matches)), locus (locus), is_invalid (false) @@ -371,8 +369,8 @@ public: } DelimType get_delim_type () const { return delim_type; } - std::vector<std::unique_ptr<MacroMatch> > &get_matches () { return matches; } - const std::vector<std::unique_ptr<MacroMatch> > &get_matches () const + std::vector<std::unique_ptr<MacroMatch>> &get_matches () { return matches; } + const std::vector<std::unique_ptr<MacroMatch>> &get_matches () const { return matches; } @@ -446,8 +444,18 @@ public: }; // A macro rules definition item AST node -class MacroRulesDefinition : public MacroItem +class MacroRulesDefinition : public VisItem { +public: + enum MacroKind + { + // Macro by Example (legacy macro rules) + MBE, + // Declarative macros 2.0 + DeclMacro, + }; + +private: std::vector<Attribute> outer_attrs; Identifier rule_name; // MacroRulesDef rules_def; @@ -460,6 +468,7 @@ class MacroRulesDefinition : public MacroItem std::function<Fragment (Location, MacroInvocData &)> associated_transcriber; // Since we can't compare std::functions, we need to use an extra boolean bool is_builtin_rule; + MacroKind kind; /** * Default function to use as an associated transcriber. This function should @@ -479,27 +488,51 @@ class MacroRulesDefinition : public MacroItem * I am not aware of the implications of this decision. The rustc spec does * mention that using the same parser for macro definitions and invocations * is "extremely self-referential and non-intuitive". */ - -public: - std::string as_string () const override; - MacroRulesDefinition (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules, - std::vector<Attribute> outer_attrs, Location locus) - : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)), + std::vector<Attribute> outer_attrs, Location locus, + MacroKind kind, Visibility vis) + : VisItem (std::move (vis), outer_attrs), + outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)), delim_type (delim_type), rules (std::move (rules)), locus (locus), - associated_transcriber (dummy_builtin), is_builtin_rule (false) + associated_transcriber (dummy_builtin), is_builtin_rule (false), + kind (kind) {} MacroRulesDefinition ( Identifier builtin_name, DelimType delim_type, - std::function<Fragment (Location, MacroInvocData &)> associated_transcriber) - : outer_attrs (std::vector<Attribute> ()), rule_name (builtin_name), + std::function<Fragment (Location, MacroInvocData &)> associated_transcriber, + MacroKind kind, Visibility vis) + : VisItem (std::move (vis), std::vector<Attribute> ()), + outer_attrs (std::vector<Attribute> ()), rule_name (builtin_name), delim_type (delim_type), rules (std::vector<MacroRule> ()), locus (Location ()), associated_transcriber (associated_transcriber), - is_builtin_rule (true) + is_builtin_rule (true), kind (kind) {} +public: + std::string as_string () const override; + + static std::unique_ptr<MacroRulesDefinition> + mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules, + std::vector<Attribute> outer_attrs, Location locus) + { + return Rust::make_unique<MacroRulesDefinition> ( + MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus, + AST::MacroRulesDefinition::MacroKind::MBE, + AST::Visibility::create_error ())); + } + + static std::unique_ptr<MacroRulesDefinition> + decl_macro (Identifier rule_name, std::vector<MacroRule> rules, + std::vector<Attribute> outer_attrs, Location locus, + Visibility vis) + { + return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition ( + rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus, + AST::MacroRulesDefinition::MacroKind::DeclMacro, vis)); + } + void accept_vis (ASTVisitor &vis) override; // Invalid if rule name is empty, so base stripping on that. @@ -545,37 +578,87 @@ protected: } }; +/** + * All builtin macros possible + */ +enum class BuiltinMacro +{ + Assert, + File, + Line, + Column, + IncludeBytes, + IncludeStr, + CompileError, + Concat, + Env, + Cfg, + Include +}; + +BuiltinMacro +builtin_macro_from_string (const std::string &identifier); + /* AST node of a macro invocation, which is replaced by the macro result at - * compile time */ + * compile time. This is technically a sum-type/tagged-union, which represents + * both classic macro invocations and builtin macro invocations. Regular macro + * invocations are expanded lazily, but builtin macro invocations need to be + * expanded eagerly, hence the differentiation. + */ class MacroInvocation : public TypeNoBounds, public Pattern, - public MacroItem, + public Item, public TraitItem, public TraitImplItem, public InherentImplItem, public ExternalItem, public ExprWithoutBlock { - std::vector<Attribute> outer_attrs; - MacroInvocData invoc_data; - Location locus; - - // Important for when we actually expand the macro - bool is_semi_coloned; - - NodeId node_id; - public: + enum class InvocKind + { + Regular, + Builtin, + }; + std::string as_string () const override; - MacroInvocation (MacroInvocData invoc_data, - std::vector<Attribute> outer_attrs, Location locus, - bool is_semi_coloned = false) - : outer_attrs (std::move (outer_attrs)), - invoc_data (std::move (invoc_data)), locus (locus), - is_semi_coloned (is_semi_coloned), - node_id (Analysis::Mappings::get ()->get_next_node_id ()) - {} + /** + * The default constructor you should use. Whenever we parse a macro call, we + * cannot possibly know whether or not this call refers to a builtin macro or + * a regular macro. With name resolution and scopes and nested macro calls, + * this is literally impossible. Hence, always start by creating a `Regular` + * MacroInvocation which will then (maybe!) become a `Builtin` macro + * invocation in the expander. + */ + static std::unique_ptr<MacroInvocation> + Regular (MacroInvocData invoc_data, std::vector<Attribute> outer_attrs, + Location locus, bool is_semi_coloned = false) + { + return std::unique_ptr<MacroInvocation> ( + new MacroInvocation (InvocKind::Regular, Optional<BuiltinMacro>::none (), + invoc_data, outer_attrs, locus, is_semi_coloned, + {})); + } + + /** + * Create a builtin macro invocation. This can only be done after macro + * name-resolution and within the macro expander, so unless you're modifying + * these visitors, you probably do not want to use this function. + */ + static std::unique_ptr<MacroInvocation> Builtin ( + BuiltinMacro kind, MacroInvocData invoc_data, + std::vector<Attribute> outer_attrs, Location locus, + std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocations + = {}, + bool is_semi_coloned = false) + { + return std::unique_ptr<MacroInvocation> ( + new MacroInvocation (InvocKind::Builtin, + Optional<BuiltinMacro>::some (kind), invoc_data, + outer_attrs, locus, is_semi_coloned, + std::move (pending_eager_invocations))); + } Location get_locus () const override final { return locus; } @@ -609,6 +692,82 @@ public: bool has_semicolon () const { return is_semi_coloned; } + InvocKind get_kind () const { return kind; } + Optional<BuiltinMacro> get_builtin_kind () const { return builtin_kind; } + + /** + * Turn the current MacroInvocation into a builtin macro invocation + */ + void map_to_builtin (BuiltinMacro macro) + { + kind = InvocKind::Builtin; + builtin_kind = Optional<BuiltinMacro>::some (macro); + } + + /** + * Get the list of pending macro invcations within the builtin macro + * invocation that should get expanded eagerly. + */ + std::vector<std::unique_ptr<MacroInvocation>> & + get_pending_eager_invocations () + { + rust_assert (kind == InvocKind::Builtin); + + return pending_eager_invocs; + } + +private: + /* Full constructor */ + MacroInvocation ( + InvocKind kind, Optional<BuiltinMacro> builtin_kind, + MacroInvocData invoc_data, std::vector<Attribute> outer_attrs, + Location locus, bool is_semi_coloned, + std::vector<std::unique_ptr<MacroInvocation>> &&pending_eager_invocs) + : TraitItem (locus), outer_attrs (std::move (outer_attrs)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()), + invoc_data (std::move (invoc_data)), is_semi_coloned (is_semi_coloned), + kind (kind), builtin_kind (builtin_kind), + pending_eager_invocs (std::move (pending_eager_invocs)) + {} + + MacroInvocation (const MacroInvocation &other) + : TraitItem (other.locus), outer_attrs (other.outer_attrs), + locus (other.locus), node_id (other.node_id), + invoc_data (other.invoc_data), is_semi_coloned (other.is_semi_coloned), + kind (other.kind), builtin_kind (other.builtin_kind) + { + if (other.kind == InvocKind::Builtin) + for (auto &pending : other.pending_eager_invocs) + pending_eager_invocs.emplace_back ( + pending->clone_macro_invocation_impl ()); + } + + std::vector<Attribute> outer_attrs; + Location locus; + NodeId node_id; + + /* The data given to the macro invocation */ + MacroInvocData invoc_data; + + /* Important for when we actually expand the macro */ + bool is_semi_coloned; + + /* Is this a builtin macro or a regular macro */ + InvocKind kind; + + /* If it is a builtin macro, which one */ + Optional<BuiltinMacro> builtin_kind = Optional<BuiltinMacro>::none (); + + /** + * Pending invocations within a builtin macro invocation. This vector is empty + * and should not be accessed for a regular macro invocation. The macro + * invocations within should be name resolved and expanded before the builtin + * macro invocation get expanded again. It is then the role of the expander to + * insert these new tokens properly in the delimited token tree and try the + * builtin transcriber once again. + */ + std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs; + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -692,6 +851,8 @@ public: return path; } + Location get_locus () const override { return path.get_locus (); } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -708,11 +869,10 @@ protected: class MetaItemSeq : public MetaItem { SimplePath path; - std::vector<std::unique_ptr<MetaItemInner> > seq; + std::vector<std::unique_ptr<MetaItemInner>> seq; public: - MetaItemSeq (SimplePath path, - std::vector<std::unique_ptr<MetaItemInner> > seq) + MetaItemSeq (SimplePath path, std::vector<std::unique_ptr<MetaItemInner>> seq) : path (std::move (path)), seq (std::move (seq)) {} @@ -745,6 +905,8 @@ public: void accept_vis (ASTVisitor &vis) override; + Location get_locus () const override { return path.get_locus (); } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -772,6 +934,8 @@ public: void accept_vis (ASTVisitor &vis) override; + Location get_locus () const override { return ident_locus; } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -814,6 +978,8 @@ public: return std::unique_ptr<MetaNameValueStr> (clone_meta_item_inner_impl ()); } + Location get_locus () const override { return ident_locus; } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -852,6 +1018,8 @@ public: void accept_vis (ASTVisitor &vis) override; + Location get_locus () const override { return ident_locus; } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -886,6 +1054,8 @@ public: void accept_vis (ASTVisitor &vis) override; + Location get_locus () const override { return ident_locus; } + bool check_cfg_predicate (const Session &session) const override; Attribute to_attribute () const override; @@ -905,18 +1075,18 @@ struct AttributeParser { private: // TODO: might as well rewrite to use lexer tokens - std::vector<std::unique_ptr<Token> > token_stream; + std::vector<std::unique_ptr<Token>> token_stream; int stream_pos; public: - AttributeParser (std::vector<std::unique_ptr<Token> > token_stream, + AttributeParser (std::vector<std::unique_ptr<Token>> token_stream, int stream_start_pos = 0) : token_stream (std::move (token_stream)), stream_pos (stream_start_pos) {} ~AttributeParser () = default; - std::vector<std::unique_ptr<MetaItemInner> > parse_meta_item_seq (); + std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq (); private: // Parses a MetaItemInner. diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index c86bdf6..a62e9b9 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -469,6 +469,10 @@ public: return pattern; } + bool is_double_reference () const { return has_two_amps; } + + bool get_is_mut () const { return is_mut; } + NodeId get_node_id () const { return node_id; } NodeId get_pattern_node_id () const override final { return node_id; } @@ -759,7 +763,7 @@ struct StructPatternElements { private: // bool has_struct_pattern_fields; - std::vector<std::unique_ptr<StructPatternField> > fields; + std::vector<std::unique_ptr<StructPatternField>> fields; bool has_struct_pattern_etc; std::vector<Attribute> struct_pattern_etc_attrs; @@ -784,7 +788,7 @@ public: // Constructor for StructPatternElements with both (potentially) StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField> > fields, + std::vector<std::unique_ptr<StructPatternField>> fields, std::vector<Attribute> etc_attrs) : fields (std::move (fields)), has_struct_pattern_etc (true), struct_pattern_etc_attrs (std::move (etc_attrs)) @@ -792,7 +796,7 @@ public: // Constructor for StructPatternElements with no StructPatternEtc StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField> > fields) + std::vector<std::unique_ptr<StructPatternField>> fields) : fields (std::move (fields)), has_struct_pattern_etc (false), struct_pattern_etc_attrs () {} @@ -828,18 +832,17 @@ public: static StructPatternElements create_empty () { return StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField> > ()); + std::vector<std::unique_ptr<StructPatternField>> ()); } std::string as_string () const; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<StructPatternField> > & - get_struct_pattern_fields () + std::vector<std::unique_ptr<StructPatternField>> &get_struct_pattern_fields () { return fields; } - const std::vector<std::unique_ptr<StructPatternField> > & + const std::vector<std::unique_ptr<StructPatternField>> & get_struct_pattern_fields () const { return fields; @@ -952,10 +955,10 @@ protected: // Class for non-ranged tuple struct pattern patterns class TupleStructItemsNoRange : public TupleStructItems { - std::vector<std::unique_ptr<Pattern> > patterns; + std::vector<std::unique_ptr<Pattern>> patterns; public: - TupleStructItemsNoRange (std::vector<std::unique_ptr<Pattern> > patterns) + TupleStructItemsNoRange (std::vector<std::unique_ptr<Pattern>> patterns) : patterns (std::move (patterns)) {} @@ -987,8 +990,8 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_patterns () { return patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const { return patterns; } @@ -1007,12 +1010,12 @@ protected: // Class for ranged tuple struct pattern patterns class TupleStructItemsRange : public TupleStructItems { - std::vector<std::unique_ptr<Pattern> > lower_patterns; - std::vector<std::unique_ptr<Pattern> > upper_patterns; + std::vector<std::unique_ptr<Pattern>> lower_patterns; + std::vector<std::unique_ptr<Pattern>> upper_patterns; public: - TupleStructItemsRange (std::vector<std::unique_ptr<Pattern> > lower_patterns, - std::vector<std::unique_ptr<Pattern> > upper_patterns) + TupleStructItemsRange (std::vector<std::unique_ptr<Pattern>> lower_patterns, + std::vector<std::unique_ptr<Pattern>> upper_patterns) : lower_patterns (std::move (lower_patterns)), upper_patterns (std::move (upper_patterns)) {} @@ -1052,21 +1055,21 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () + std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () { return lower_patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const { return lower_patterns; } // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () + std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () { return upper_patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const { return upper_patterns; } @@ -1229,10 +1232,10 @@ TuplePatternItemsSingle(*this); // Class representing TuplePattern patterns where there are multiple patterns class TuplePatternItemsMultiple : public TuplePatternItems { - std::vector<std::unique_ptr<Pattern> > patterns; + std::vector<std::unique_ptr<Pattern>> patterns; public: - TuplePatternItemsMultiple (std::vector<std::unique_ptr<Pattern> > patterns) + TuplePatternItemsMultiple (std::vector<std::unique_ptr<Pattern>> patterns) : patterns (std::move (patterns)) {} @@ -1264,8 +1267,8 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_patterns () { return patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const { return patterns; } @@ -1287,13 +1290,12 @@ protected: // Class representing TuplePattern patterns where there are a range of patterns class TuplePatternItemsRanged : public TuplePatternItems { - std::vector<std::unique_ptr<Pattern> > lower_patterns; - std::vector<std::unique_ptr<Pattern> > upper_patterns; + std::vector<std::unique_ptr<Pattern>> lower_patterns; + std::vector<std::unique_ptr<Pattern>> upper_patterns; public: - TuplePatternItemsRanged ( - std::vector<std::unique_ptr<Pattern> > lower_patterns, - std::vector<std::unique_ptr<Pattern> > upper_patterns) + TuplePatternItemsRanged (std::vector<std::unique_ptr<Pattern>> lower_patterns, + std::vector<std::unique_ptr<Pattern>> upper_patterns) : lower_patterns (std::move (lower_patterns)), upper_patterns (std::move (upper_patterns)) {} @@ -1334,21 +1336,21 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () + std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () { return lower_patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const { return lower_patterns; } // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () + std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () { return upper_patterns; } - const std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const { return upper_patterns; } @@ -1499,14 +1501,14 @@ protected: // AST node representing patterns that can match slices and arrays class SlicePattern : public Pattern { - std::vector<std::unique_ptr<Pattern> > items; + std::vector<std::unique_ptr<Pattern>> items; Location locus; NodeId node_id; public: std::string as_string () const override; - SlicePattern (std::vector<std::unique_ptr<Pattern> > items, Location locus) + SlicePattern (std::vector<std::unique_ptr<Pattern>> items, Location locus) : items (std::move (items)), locus (locus), node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} @@ -1542,8 +1544,8 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern> > &get_items () { return items; } - const std::vector<std::unique_ptr<Pattern> > &get_items () const + std::vector<std::unique_ptr<Pattern>> &get_items () { return items; } + const std::vector<std::unique_ptr<Pattern>> &get_items () const { return items; } @@ -1561,6 +1563,72 @@ protected: } }; +// AST node for alternate patterns +// joins together what are technically 'PatternNoTopAlt's +class AltPattern : public Pattern +{ + std::vector<std::unique_ptr<Pattern>> alts; + Location locus; + NodeId node_id; + +public: + std::string as_string () const override; + + AltPattern (std::vector<std::unique_ptr<Pattern>> alts, Location locus) + : alts (std::move (alts)), locus (locus), + node_id (Analysis::Mappings::get ()->get_next_node_id ()) + {} + + // Copy constructor with vector clone + AltPattern (AltPattern const &other) : locus (other.locus) + { + node_id = other.node_id; + alts.reserve (other.alts.size ()); + for (const auto &e : other.alts) + alts.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to vector clone + AltPattern &operator= (AltPattern const &other) + { + locus = other.locus; + node_id = other.node_id; + + alts.reserve (other.alts.size ()); + for (const auto &e : other.alts) + alts.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + AltPattern (AltPattern &&other) = default; + AltPattern &operator= (AltPattern &&other) = default; + + Location get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern>> &get_alts () { return alts; } + const std::vector<std::unique_ptr<Pattern>> &get_alts () const + { + return alts; + } + + NodeId get_node_id () const { return node_id; } + + NodeId get_pattern_node_id () const override final { return node_id; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + AltPattern *clone_pattern_impl () const override + { + return new AltPattern (*this); + } +}; + // Moved definition to rust-path.h class PathPattern; diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 568abf9..c108661 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -457,9 +457,7 @@ HIRCompileBase::compile_locals_for_block (Context *ctx, Resolver::Rib &rib, // compile the local tree type = TyTyResolveCompile::compile (ctx, tyty); - Bvariable *compiled - = CompileVarDecl::compile (fndecl, type, pattern, ctx); - locals.push_back (compiled); + CompileVarDecl::compile (fndecl, type, pattern, locals, ctx); } return locals; } diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 436fc92..d7945db 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -26,6 +26,7 @@ #include "rust-compile-block.h" #include "rust-compile-implitem.h" #include "rust-constexpr.h" +#include "rust-unify.h" #include "rust-gcc.h" #include "fold-const.h" @@ -1341,30 +1342,6 @@ CompileExpr::visit (HIR::MatchExpr &expr) // SWITCH_ALL_CASES_P is true if the switch includes a default label or the // case label ranges cover all possible values of the condition expression - /* Switch expression. - - TREE_TYPE is the original type of the condition, before any - language required type conversions. It may be NULL, in which case - the original type and final types are assumed to be the same. - - Operand 0 is the expression used to perform the branch, - Operand 1 is the body of the switch, which probably contains - CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2 - must not be NULL. */ - // DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2) - - /* Used to represent a case label. - - Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the label - is a 'default' label. - Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple - (one-value) case label. If it is non-NULL_TREE, the case is a range. - Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL. - Operand 3 is CASE_CHAIN. This operand is only used in tree-cfg.cc to - speed up the lookup of case labels which use a particular edge in - the control flow graph. */ - // DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4) - TyTy::TypeKind scrutinee_kind = check_match_scrutinee (expr, ctx); if (scrutinee_kind == TyTy::TypeKind::ERROR) { @@ -2030,7 +2007,10 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, { TyTy::BaseType *infer_impl_call = candidate_call->infer_substitions (expr_locus); - monomorphized = infer_impl_call->unify (fntype); + monomorphized = Resolver::UnifyRules::Resolve ( + TyTy::TyWithLocation (infer_impl_call), + TyTy::TyWithLocation (fntype), expr_locus, true /* commit */, + true /* emit_errors */); } return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized); diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h index 0d99814..10e8b67 100644 --- a/gcc/rust/backend/rust-compile-fnparam.h +++ b/gcc/rust/backend/rust-compile-fnparam.h @@ -39,7 +39,6 @@ public: void visit (HIR::TupleStructPattern &) override; // Empty visit for unused Pattern HIR nodes. - void visit (HIR::GroupedPattern &) override {} void visit (HIR::LiteralPattern &) override {} void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index fc70d4b..d98f7be 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -329,5 +329,134 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) } } +void +CompilePatternLet::visit (HIR::IdentifierPattern &pattern) +{ + Bvariable *var = nullptr; + rust_assert ( + ctx->lookup_var_decl (pattern.get_pattern_mappings ().get_hirid (), &var)); + + auto fnctx = ctx->peek_fn (); + if (ty->is_unit ()) + { + ctx->add_statement (init_expr); + + tree stmt_type = TyTyResolveCompile::compile (ctx, ty); + + auto unit_type_init_expr + = ctx->get_backend ()->constructor_expression (stmt_type, false, {}, -1, + rval_locus); + auto s = ctx->get_backend ()->init_statement (fnctx.fndecl, var, + unit_type_init_expr); + ctx->add_statement (s); + } + else + { + auto s + = ctx->get_backend ()->init_statement (fnctx.fndecl, var, init_expr); + ctx->add_statement (s); + } +} + +void +CompilePatternLet::visit (HIR::WildcardPattern &pattern) +{ + tree init_stmt = NULL; + tree stmt_type = TyTyResolveCompile::compile (ctx, ty); + + ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, + stmt_type, init_expr, false, + pattern.get_locus (), &init_stmt); + + ctx->add_statement (init_stmt); +} + +void +CompilePatternLet::visit (HIR::TuplePattern &pattern) +{ + rust_assert (pattern.has_tuple_pattern_items ()); + + tree tuple_type = TyTyResolveCompile::compile (ctx, ty); + tree init_stmt; + Bvariable *tmp_var + = ctx->get_backend ()->temporary_variable (ctx->peek_fn ().fndecl, + NULL_TREE, tuple_type, init_expr, + false, pattern.get_locus (), + &init_stmt); + tree access_expr + = ctx->get_backend ()->var_expression (tmp_var, pattern.get_locus ()); + ctx->add_statement (init_stmt); + + switch (pattern.get_items ()->get_pattern_type ()) + { + case HIR::TuplePatternItems::TuplePatternItemType::RANGED: { + size_t tuple_idx = 0; + auto &items + = static_cast<HIR::TuplePatternItemsRanged &> (*pattern.get_items ()); + + auto &items_lower = items.get_lower_patterns (); + auto &items_upper = items.get_upper_patterns (); + + for (auto &sub : items_lower) + { + TyTy::BaseType *ty_sub = nullptr; + HirId pattern_id = pattern.get_pattern_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (pattern_id, &ty_sub); + rust_assert (ok); + + tree sub_init = ctx->get_backend ()->struct_field_expression ( + access_expr, tuple_idx, sub->get_locus ()); + CompilePatternLet::Compile (sub.get (), sub_init, ty_sub, + rval_locus, ctx); + tuple_idx++; + } + + rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE); + tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields () + - items_upper.size (); + + for (auto &sub : items_upper) + { + TyTy::BaseType *ty_sub = nullptr; + HirId pattern_id = pattern.get_pattern_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (pattern_id, &ty_sub); + rust_assert (ok); + + tree sub_init = ctx->get_backend ()->struct_field_expression ( + access_expr, tuple_idx, sub->get_locus ()); + CompilePatternLet::Compile (sub.get (), sub_init, ty_sub, + rval_locus, ctx); + tuple_idx++; + } + + return; + } + case HIR::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + size_t tuple_idx = 0; + auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( + *pattern.get_items ()); + + for (auto &sub : items.get_patterns ()) + { + TyTy::BaseType *ty_sub = nullptr; + HirId pattern_id = pattern.get_pattern_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (pattern_id, &ty_sub); + rust_assert (ok); + + tree sub_init = ctx->get_backend ()->struct_field_expression ( + access_expr, tuple_idx, sub->get_locus ()); + CompilePatternLet::Compile (sub.get (), sub_init, ty_sub, + rval_locus, ctx); + tuple_idx++; + } + + return; + } + default: { + gcc_unreachable (); + } + } +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index 22812a4..8f44b7b 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -40,7 +40,6 @@ public: void visit (HIR::RangePattern &pattern) override; // Empty visit for unused Pattern HIR nodes. - void visit (HIR::GroupedPattern &) override {} void visit (HIR::IdentifierPattern &) override {} void visit (HIR::LiteralPattern &) override; void visit (HIR::QualifiedPathInExpression &) override {} @@ -72,7 +71,6 @@ public: void visit (HIR::TupleStructPattern &pattern) override; // Empty visit for unused Pattern HIR nodes. - void visit (HIR::GroupedPattern &) override {} void visit (HIR::IdentifierPattern &) override {} void visit (HIR::LiteralPattern &) override {} void visit (HIR::PathInExpression &) override {} @@ -91,5 +89,81 @@ protected: tree match_scrutinee_expr; }; +class CompilePatternLet : public HIRCompileBase, public HIR::HIRPatternVisitor +{ +public: + static void Compile (HIR::Pattern *pattern, tree init_expr, + TyTy::BaseType *ty, Location rval_locus, Context *ctx) + { + CompilePatternLet compiler (ctx, init_expr, ty, rval_locus); + pattern->accept_vis (compiler); + } + + void visit (HIR::IdentifierPattern &) override; + void visit (HIR::WildcardPattern &) override; + void visit (HIR::TuplePattern &) override; + + // check for unimplemented Pattern HIR nodes. + void visit (HIR::LiteralPattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "literal pattern let statements not supported"); + } + + void visit (HIR::PathInExpression &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "path-in-expression pattern let statements not supported"); + } + + void visit (HIR::QualifiedPathInExpression &pattern) override + { + rust_sorry_at ( + pattern.get_locus (), + "qualified-path-in-expression pattern let statements not supported"); + } + + void visit (HIR::RangePattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "range pattern let statements not supported"); + } + + void visit (HIR::ReferencePattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "reference pattern let statements not supported"); + } + + void visit (HIR::SlicePattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "slice pattern let statements not supported"); + } + + void visit (HIR::StructPattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "struct pattern let statements not supported"); + } + + void visit (HIR::TupleStructPattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "tuple-struct pattern let statements not supported"); + } + +protected: + CompilePatternLet (Context *ctx, tree init_expr, TyTy::BaseType *ty, + Location rval_locus) + : HIRCompileBase (ctx), init_expr (init_expr), ty (ty), + rval_locus (rval_locus) + {} + + tree init_expr; + TyTy::BaseType *ty; + Location rval_locus; +}; + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h index 67ff7ee..6aec7be 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.h +++ b/gcc/rust/backend/rust-compile-resolve-path.h @@ -45,7 +45,6 @@ public: void visit (HIR::QualifiedPathInExpression &expr) override; // Empty visit for unused Pattern HIR nodes. - void visit (HIR::GroupedPattern &) override {} void visit (HIR::IdentifierPattern &) override {} void visit (HIR::LiteralPattern &) override {} void visit (HIR::RangePattern &) override {} diff --git a/gcc/rust/backend/rust-compile-stmt.cc b/gcc/rust/backend/rust-compile-stmt.cc index 3fc2528..6bb4ead 100644 --- a/gcc/rust/backend/rust-compile-stmt.cc +++ b/gcc/rust/backend/rust-compile-stmt.cc @@ -16,6 +16,7 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-compile-pattern.h" #include "rust-compile-stmt.h" #include "rust-compile-expr.h" @@ -53,7 +54,7 @@ CompileStmt::visit (HIR::LetStmt &stmt) if (!stmt.has_init_expr ()) return; - const HIR::Pattern &stmt_pattern = *stmt.get_pattern (); + HIR::Pattern &stmt_pattern = *stmt.get_pattern (); HirId stmt_id = stmt_pattern.get_pattern_mappings ().get_hirid (); TyTy::BaseType *ty = nullptr; @@ -65,15 +66,6 @@ CompileStmt::visit (HIR::LetStmt &stmt) return; } - Bvariable *var = nullptr; - if (!ctx->lookup_var_decl (stmt_id, &var)) - { - // FIXME this should be an assertion instead and use error mark node - rust_fatal_error (stmt.get_locus (), - "failed to lookup compiled variable declaration"); - return; - } - tree init = CompileExpr::Compile (stmt.get_init_expr (), ctx); // FIXME use error_mark_node, check that CompileExpr returns error_mark_node // on failure and make this an assertion @@ -84,7 +76,6 @@ CompileStmt::visit (HIR::LetStmt &stmt) bool ok = ctx->get_tyctx ()->lookup_type ( stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual); rust_assert (ok); - tree stmt_type = TyTyResolveCompile::compile (ctx, ty); Location lvalue_locus = stmt.get_pattern ()->get_locus (); Location rvalue_locus = stmt.get_init_expr ()->get_locus (); @@ -92,23 +83,7 @@ CompileStmt::visit (HIR::LetStmt &stmt) init = coercion_site (stmt.get_mappings ().get_hirid (), init, actual, expected, lvalue_locus, rvalue_locus); - auto fnctx = ctx->peek_fn (); - if (ty->is_unit ()) - { - ctx->add_statement (init); - - auto unit_type_init_expr - = ctx->get_backend ()->constructor_expression (stmt_type, false, {}, -1, - rvalue_locus); - auto s = ctx->get_backend ()->init_statement (fnctx.fndecl, var, - unit_type_init_expr); - ctx->add_statement (s); - } - else - { - auto s = ctx->get_backend ()->init_statement (fnctx.fndecl, var, init); - ctx->add_statement (s); - } + CompilePatternLet::Compile (&stmt_pattern, init, ty, rvalue_locus, ctx); } } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h index 00146a4..13b429d 100644 --- a/gcc/rust/backend/rust-compile-var-decl.h +++ b/gcc/rust/backend/rust-compile-var-decl.h @@ -30,12 +30,11 @@ class CompileVarDecl : public HIRCompileBase, public HIR::HIRPatternVisitor using HIR::HIRPatternVisitor::visit; public: - static ::Bvariable *compile (tree fndecl, tree translated_type, - HIR::Pattern *pattern, Context *ctx) + static void compile (tree fndecl, tree translated_type, HIR::Pattern *pattern, + std::vector<Bvariable *> &locals, Context *ctx) { - CompileVarDecl compiler (ctx, fndecl, translated_type); + CompileVarDecl compiler (ctx, fndecl, translated_type, locals); pattern->accept_vis (compiler); - return compiler.compiled_variable; } void visit (HIR::IdentifierPattern &pattern) override @@ -43,30 +42,18 @@ public: if (!pattern.is_mut ()) translated_type = ctx->get_backend ()->immutable_type (translated_type); - compiled_variable + Bvariable *var = ctx->get_backend ()->local_variable (fndecl, pattern.get_identifier (), translated_type, NULL /*decl_var*/, pattern.get_locus ()); HirId stmt_id = pattern.get_pattern_mappings ().get_hirid (); - ctx->insert_var_decl (stmt_id, compiled_variable); - } - - void visit (HIR::WildcardPattern &pattern) override - { - translated_type = ctx->get_backend ()->immutable_type (translated_type); + ctx->insert_var_decl (stmt_id, var); - compiled_variable - = ctx->get_backend ()->local_variable (fndecl, "_", translated_type, - NULL /*decl_var*/, - pattern.get_locus ()); - - HirId stmt_id = pattern.get_pattern_mappings ().get_hirid (); - ctx->insert_var_decl (stmt_id, compiled_variable); + locals.push_back (var); } // Empty visit for unused Pattern HIR nodes. - void visit (HIR::GroupedPattern &) override {} void visit (HIR::LiteralPattern &) override {} void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} @@ -76,17 +63,19 @@ public: void visit (HIR::StructPattern &) override {} void visit (HIR::TuplePattern &) override {} void visit (HIR::TupleStructPattern &) override {} + void visit (HIR::WildcardPattern &) override {} private: - CompileVarDecl (Context *ctx, tree fndecl, tree translated_type) + CompileVarDecl (Context *ctx, tree fndecl, tree translated_type, + std::vector<Bvariable *> &locals) : HIRCompileBase (ctx), fndecl (fndecl), translated_type (translated_type), - compiled_variable (ctx->get_backend ()->error_variable ()) + locals (locals) {} tree fndecl; tree translated_type; - Bvariable *compiled_variable; + std::vector<Bvariable *> &locals; }; } // namespace Compile diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc index becb9fd..30afaf9 100644 --- a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc @@ -63,7 +63,7 @@ VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction, NodeId ref_node_id = UNKNOWN_NODEID; if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) { - invalid_path.emit_error (); + invalid_path.emit (); return false; } // FIXME: Add a hint here if we can find the path in another scope, such as @@ -77,7 +77,7 @@ VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction, auto module = mappings.lookup_module (ref); if (!module) { - invalid_path.emit_error (); + invalid_path.emit (); return false; } diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 576c1b1..3752cf3 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -835,10 +835,6 @@ ConstChecker::visit (TuplePattern &) {} void -ConstChecker::visit (GroupedPattern &) -{} - -void ConstChecker::visit (SlicePattern &) {} @@ -898,8 +894,12 @@ ConstChecker::visit (RawPointerType &) {} void -ConstChecker::visit (ReferenceType &) -{} +ConstChecker::visit (ReferenceType &type) +{ + if (const_context.is_in_context () && type.is_mut ()) + rust_error_at (type.get_locus (), + "mutable references are not allowed in constant functions"); +} void ConstChecker::visit (ArrayType &type) diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 2381738..e040236 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -186,7 +186,6 @@ private: virtual void visit (TuplePatternItemsMultiple &tuple_items) override; virtual void visit (TuplePatternItemsRanged &tuple_items) override; virtual void visit (TuplePattern &pattern) override; - virtual void visit (GroupedPattern &pattern) override; virtual void visit (SlicePattern &pattern) override; virtual void visit (EmptyStmt &stmt) override; virtual void visit (LetStmt &stmt) override; diff --git a/gcc/rust/checks/errors/rust-feature-gate.cc b/gcc/rust/checks/errors/rust-feature-gate.cc new file mode 100644 index 0000000..bd01b52 --- /dev/null +++ b/gcc/rust/checks/errors/rust-feature-gate.cc @@ -0,0 +1,108 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-feature-gate.h" +#include "rust-abi.h" + +namespace Rust { + +void +FeatureGate::check (AST::Crate &crate) +{ + valid_features.clear (); + + for (const auto &attr : crate.inner_attrs) + { + if (attr.get_path ().as_string () == "feature") + { + const auto &attr_input = attr.get_attr_input (); + auto type = attr_input.get_attr_input_type (); + if (type == AST::AttrInput::AttrInputType::TOKEN_TREE) + { + const auto &option = static_cast<const AST::DelimTokenTree &> ( + attr.get_attr_input ()); + std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item ( + option.parse_to_meta_item ()); + for (const auto &item : meta_item->get_items ()) + { + const auto &name_str = item->as_string (); + auto tname = Feature::as_name (name_str); + if (!tname.is_none ()) + { + auto name = tname.get (); + valid_features.insert (name); + } + + else + rust_error_at (item->get_locus (), "unknown feature '%s'", + name_str.c_str ()); + } + } + } + } + + auto &items = crate.items; + for (auto it = items.begin (); it != items.end (); it++) + { + auto &item = *it; + item->accept_vis (*this); + } +} + +void +FeatureGate::gate (Feature::Name name, Location loc, + const std::string &error_msg) +{ + if (!valid_features.count (name)) + { + auto feature = Feature::create (name); + auto issue = feature.issue (); + if (issue > 0) + { + const char *fmt_str + = "%s. see issue %ld " + "<https://github.com/rust-lang/rust/issues/%ld> for more " + "information. add `#![feature(%s)]` to the crate attributes to " + "enable."; + rust_error_at (loc, fmt_str, error_msg.c_str (), issue, issue, + feature.as_string ().c_str ()); + } + else + { + const char *fmt_str + = "%s. add `#![feature(%s)]` to the crate attributes to enable."; + rust_error_at (loc, fmt_str, error_msg.c_str (), + feature.as_string ().c_str ()); + } + } +} + +void +FeatureGate::visit (AST::ExternBlock &block) +{ + if (block.has_abi ()) + { + const auto abi = block.get_abi (); + + if (get_abi_from_string (abi) == ABI::INTRINSIC) + gate (Feature::Name::INTRINSICS, block.get_locus (), + "intrinsics are subject to change"); + } +} + +} // namespace Rust
\ No newline at end of file diff --git a/gcc/rust/checks/errors/rust-feature-gate.h b/gcc/rust/checks/errors/rust-feature-gate.h new file mode 100644 index 0000000..20af147 --- /dev/null +++ b/gcc/rust/checks/errors/rust-feature-gate.h @@ -0,0 +1,197 @@ +// Copyright (C) 2020-2023 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_FEATURE_GATE_H +#define RUST_FEATURE_GATE_H + +#include "rust-ast-visitor.h" +#include "rust-ast-full.h" +#include "rust-feature.h" + +namespace Rust { + +struct Feature; + +class FeatureGate : public AST::ASTVisitor +{ +public: + FeatureGate () {} + + void check (AST::Crate &crate); + + void visit (AST::Token &tok) override {} + void visit (AST::DelimTokenTree &delim_tok_tree) override {} + void visit (AST::AttrInputMetaItemContainer &input) override {} + void visit (AST::IdentifierExpr &ident_expr) override {} + void visit (AST::Lifetime &lifetime) override {} + void visit (AST::LifetimeParam &lifetime_param) override {} + void visit (AST::ConstGenericParam &const_param) override {} + void visit (AST::PathInExpression &path) override {} + void visit (AST::TypePathSegment &segment) override {} + void visit (AST::TypePathSegmentGeneric &segment) override {} + void visit (AST::TypePathSegmentFunction &segment) override {} + void visit (AST::TypePath &path) override {} + void visit (AST::QualifiedPathInExpression &path) override {} + void visit (AST::QualifiedPathInType &path) override {} + void visit (AST::LiteralExpr &expr) override {} + void visit (AST::AttrInputLiteral &attr_input) override {} + void visit (AST::MetaItemLitExpr &meta_item) override {} + void visit (AST::MetaItemPathLit &meta_item) override {} + void visit (AST::BorrowExpr &expr) override {} + void visit (AST::DereferenceExpr &expr) override {} + void visit (AST::ErrorPropagationExpr &expr) override {} + void visit (AST::NegationExpr &expr) override {} + void visit (AST::ArithmeticOrLogicalExpr &expr) override {} + void visit (AST::ComparisonExpr &expr) override {} + void visit (AST::LazyBooleanExpr &expr) override {} + void visit (AST::TypeCastExpr &expr) override {} + void visit (AST::AssignmentExpr &expr) override {} + void visit (AST::CompoundAssignmentExpr &expr) override {} + void visit (AST::GroupedExpr &expr) override {} + void visit (AST::ArrayElemsValues &elems) override {} + void visit (AST::ArrayElemsCopied &elems) override {} + void visit (AST::ArrayExpr &expr) override {} + void visit (AST::ArrayIndexExpr &expr) override {} + void visit (AST::TupleExpr &expr) override {} + void visit (AST::TupleIndexExpr &expr) override {} + void visit (AST::StructExprStruct &expr) override {} + void visit (AST::StructExprFieldIdentifier &field) override {} + void visit (AST::StructExprFieldIdentifierValue &field) override {} + void visit (AST::StructExprFieldIndexValue &field) override {} + void visit (AST::StructExprStructFields &expr) override {} + void visit (AST::StructExprStructBase &expr) override {} + void visit (AST::CallExpr &expr) override {} + void visit (AST::MethodCallExpr &expr) override {} + void visit (AST::FieldAccessExpr &expr) override {} + void visit (AST::ClosureExprInner &expr) override {} + void visit (AST::BlockExpr &expr) override {} + void visit (AST::ClosureExprInnerTyped &expr) override {} + void visit (AST::ContinueExpr &expr) override {} + void visit (AST::BreakExpr &expr) override {} + void visit (AST::RangeFromToExpr &expr) override {} + void visit (AST::RangeFromExpr &expr) override {} + void visit (AST::RangeToExpr &expr) override {} + void visit (AST::RangeFullExpr &expr) override {} + void visit (AST::RangeFromToInclExpr &expr) override {} + void visit (AST::RangeToInclExpr &expr) override {} + void visit (AST::ReturnExpr &expr) override {} + void visit (AST::UnsafeBlockExpr &expr) override {} + void visit (AST::LoopExpr &expr) override {} + void visit (AST::WhileLoopExpr &expr) override {} + void visit (AST::WhileLetLoopExpr &expr) override {} + void visit (AST::ForLoopExpr &expr) override {} + void visit (AST::IfExpr &expr) override {} + void visit (AST::IfExprConseqElse &expr) override {} + void visit (AST::IfExprConseqIf &expr) override {} + void visit (AST::IfExprConseqIfLet &expr) override {} + void visit (AST::IfLetExpr &expr) override {} + void visit (AST::IfLetExprConseqElse &expr) override {} + void visit (AST::IfLetExprConseqIf &expr) override {} + void visit (AST::IfLetExprConseqIfLet &expr) override {} + void visit (AST::MatchExpr &expr) override {} + void visit (AST::AwaitExpr &expr) override {} + void visit (AST::AsyncBlockExpr &expr) override {} + void visit (AST::TypeParam ¶m) override {} + void visit (AST::LifetimeWhereClauseItem &item) override {} + void visit (AST::TypeBoundWhereClauseItem &item) override {} + void visit (AST::Method &method) override {} + void visit (AST::Module &module) override {} + void visit (AST::ExternCrate &crate) override {} + void visit (AST::UseTreeGlob &use_tree) override {} + void visit (AST::UseTreeList &use_tree) override {} + void visit (AST::UseTreeRebind &use_tree) override {} + void visit (AST::UseDeclaration &use_decl) override {} + void visit (AST::Function &function) override {} + void visit (AST::TypeAlias &type_alias) override {} + void visit (AST::StructStruct &struct_item) override {} + void visit (AST::TupleStruct &tuple_struct) override {} + void visit (AST::EnumItem &item) override {} + void visit (AST::EnumItemTuple &item) override {} + void visit (AST::EnumItemStruct &item) override {} + void visit (AST::EnumItemDiscriminant &item) override {} + void visit (AST::Enum &enum_item) override {} + void visit (AST::Union &union_item) override {} + void visit (AST::ConstantItem &const_item) override {} + void visit (AST::StaticItem &static_item) override {} + void visit (AST::TraitItemFunc &item) override {} + void visit (AST::TraitItemMethod &item) override {} + void visit (AST::TraitItemConst &item) override {} + void visit (AST::TraitItemType &item) override {} + void visit (AST::Trait &trait) override {} + void visit (AST::InherentImpl &impl) override {} + void visit (AST::TraitImpl &impl) override {} + void visit (AST::ExternalStaticItem &item) override {} + void visit (AST::ExternalFunctionItem &item) override {} + void visit (AST::ExternBlock &block) override; + void visit (AST::MacroMatchFragment &match) override {} + void visit (AST::MacroMatchRepetition &match) override {} + void visit (AST::MacroMatcher &matcher) override {} + void visit (AST::MacroRulesDefinition &rules_def) override {} + void visit (AST::MacroInvocation ¯o_invoc) override {} + void visit (AST::MetaItemPath &meta_item) override {} + void visit (AST::MetaItemSeq &meta_item) override {} + void visit (AST::MetaWord &meta_item) override {} + void visit (AST::MetaNameValueStr &meta_item) override {} + void visit (AST::MetaListPaths &meta_item) override {} + void visit (AST::MetaListNameValueStr &meta_item) override {} + void visit (AST::LiteralPattern &pattern) override {} + void visit (AST::IdentifierPattern &pattern) override {} + void visit (AST::WildcardPattern &pattern) override {} + void visit (AST::RangePatternBoundLiteral &bound) override {} + void visit (AST::RangePatternBoundPath &bound) override {} + void visit (AST::RangePatternBoundQualPath &bound) override {} + void visit (AST::RangePattern &pattern) override {} + void visit (AST::ReferencePattern &pattern) override {} + void visit (AST::StructPatternFieldTuplePat &field) override {} + void visit (AST::StructPatternFieldIdentPat &field) override {} + void visit (AST::StructPatternFieldIdent &field) override {} + void visit (AST::StructPattern &pattern) override {} + void visit (AST::TupleStructItemsNoRange &tuple_items) override {} + void visit (AST::TupleStructItemsRange &tuple_items) override {} + void visit (AST::TupleStructPattern &pattern) override {} + void visit (AST::TuplePatternItemsMultiple &tuple_items) override {} + void visit (AST::TuplePatternItemsRanged &tuple_items) override {} + void visit (AST::TuplePattern &pattern) override {} + void visit (AST::GroupedPattern &pattern) override {} + void visit (AST::SlicePattern &pattern) override {} + void visit (AST::AltPattern &pattern) override {} + void visit (AST::EmptyStmt &stmt) override {} + void visit (AST::LetStmt &stmt) override {} + void visit (AST::ExprStmtWithoutBlock &stmt) override {} + void visit (AST::ExprStmtWithBlock &stmt) override {} + void visit (AST::TraitBound &bound) override {} + void visit (AST::ImplTraitType &type) override {} + void visit (AST::TraitObjectType &type) override {} + void visit (AST::ParenthesisedType &type) override {} + void visit (AST::ImplTraitTypeOneBound &type) override {} + void visit (AST::TraitObjectTypeOneBound &type) override {} + void visit (AST::TupleType &type) override {} + void visit (AST::NeverType &type) override {} + void visit (AST::RawPointerType &type) override {} + void visit (AST::ReferenceType &type) override {} + void visit (AST::ArrayType &type) override {} + void visit (AST::SliceType &type) override {} + void visit (AST::InferredType &type) override {} + void visit (AST::BareFunctionType &type) override {} + +private: + void gate (Feature::Name name, Location loc, const std::string &error_msg); + std::set<Feature::Name> valid_features; +}; +} // namespace Rust +#endif diff --git a/gcc/rust/checks/errors/rust-feature.cc b/gcc/rust/checks/errors/rust-feature.cc new file mode 100644 index 0000000..81689d9 --- /dev/null +++ b/gcc/rust/checks/errors/rust-feature.cc @@ -0,0 +1,66 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-feature.h" +#include "rust-session-manager.h" + +namespace Rust { + +Feature +Feature::create (Feature::Name name) +{ + switch (name) + { + case Feature::Name::ASSOCIATED_TYPE_BOUNDS: + return Feature (Feature::Name::ASSOCIATED_TYPE_BOUNDS, + Feature::State::ACCEPTED, "associated_type_bounds", + "1.34.0", 52662, + Optional<CompileOptions::Edition>::none (), ""); + case Feature::Name::INTRINSICS: + return Feature (Feature::Name::INTRINSICS, Feature::State::ACCEPTED, + "intrinsics", "1.0.0", 0, + Optional<CompileOptions::Edition>::none (), ""); + case Feature::Name::RUSTC_ATTRS: + return Feature (Feature::Name::RUSTC_ATTRS, Feature::State::ACCEPTED, + "rustc_attrs", "1.0.0", 0, + Optional<CompileOptions::Edition>::none (), ""); + case Feature::Name::DECL_MACRO: + return Feature (Feature::Name::DECL_MACRO, Feature::State::ACCEPTED, + "decl_macro", "1.0.0", 0, + Optional<CompileOptions::Edition>::none (), ""); + default: + gcc_unreachable (); + } +} + +const std::map<std::string, Feature::Name> Feature::name_hash_map = { + {"associated_type_bounds", Feature::Name::ASSOCIATED_TYPE_BOUNDS}, + {"intrinsics", Feature::Name::INTRINSICS}, + {"rustc_attrs", Feature::Name::RUSTC_ATTRS}, + {"decl_macro", Feature::Name::DECL_MACRO}, +}; + +Optional<Feature::Name> +Feature::as_name (const std::string &name) +{ + if (Feature::name_hash_map.count (name)) + return Optional<Feature::Name>::some (Feature::name_hash_map.at (name)); + return Optional<Feature::Name>::none (); +} + +} // namespace Rust
\ No newline at end of file diff --git a/gcc/rust/checks/errors/rust-feature.h b/gcc/rust/checks/errors/rust-feature.h new file mode 100644 index 0000000..7bd76c0 --- /dev/null +++ b/gcc/rust/checks/errors/rust-feature.h @@ -0,0 +1,77 @@ +// Copyright (C) 2020-2023 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_FEATURE_H +#define RUST_FEATURE_H + +#include "rust-session-manager.h" +#include "rust-optional.h" + +namespace Rust { + +class Feature +{ +public: + enum class State + { + ACCEPTED, + ACTIVE, + REMOVED, + STABILIZED, + }; + + enum class Name + { + ASSOCIATED_TYPE_BOUNDS, + INTRINSICS, + RUSTC_ATTRS, + DECL_MACRO, + }; + + const std::string &as_string () { return m_name_str; } + Name name () { return m_name; } + const std::string &description () { return m_description; } + State state () { return m_state; } + uint64_t issue () { return m_issue; } + + static Optional<Name> as_name (const std::string &name); + static Feature create (Name name); + +private: + Feature (Name name, State state, const char *name_str, + const char *rustc_since, uint64_t issue_number, + const Optional<CompileOptions::Edition> &edition, + const char *description) + : m_state (state), m_name (name), m_name_str (name_str), + m_rustc_since (rustc_since), m_issue (issue_number), edition (edition), + m_description (description) + {} + + State m_state; + Name m_name; + std::string m_name_str; + std::string m_rustc_since; + uint64_t m_issue; + Optional<CompileOptions::Edition> edition; + std::string m_description; + + static const std::map<std::string, Name> name_hash_map; +}; + +} // namespace Rust +#endif
\ No newline at end of file diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 9480863..ff7a0b3 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -179,6 +179,31 @@ UnsafeChecker::check_function_call (HirId node_id, Location locus) locus); } +static void +check_target_attr (HIR::Function *fn, Location locus) +{ + if (std::any_of (fn->get_outer_attrs ().begin (), + fn->get_outer_attrs ().end (), + [] (const AST::Attribute &attr) { + return attr.get_path ().as_string () == "target_feature"; + })) + rust_error_at (locus, + "call to function with %<#[target_feature]%> requires " + "unsafe function or block"); +} + +void +UnsafeChecker::check_function_attr (HirId node_id, Location locus) +{ + if (unsafe_context.is_in_context ()) + return; + + auto maybe_fn = mappings.lookup_hir_item (node_id); + + if (maybe_fn && maybe_fn->get_item_kind () == Item::ItemKind::Function) + check_target_attr (static_cast<Function *> (maybe_fn), locus); +} + void UnsafeChecker::visit (Lifetime &) {} @@ -398,11 +423,13 @@ UnsafeChecker::visit (CallExpr &expr) rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id)); - // At this point we have the function's HIR Id. There are two checks we + // At this point we have the function's HIR Id. There are three checks we // must perform: // 1. The function is an unsafe one // 2. The function is an extern one + // 3. The function is marked with a target_feature attribute check_function_call (definition_id, expr.get_locus ()); + check_function_attr (definition_id, expr.get_locus ()); if (expr.has_params ()) for (auto &arg : expr.get_arguments ()) @@ -875,10 +902,6 @@ UnsafeChecker::visit (TuplePattern &) {} void -UnsafeChecker::visit (GroupedPattern &) -{} - -void UnsafeChecker::visit (SlicePattern &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 9df44db..ce270c0 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -46,6 +46,11 @@ private: */ void check_function_call (HirId node_id, Location locus); + /** + * Check if any unsafe attributes are present on a function + */ + void check_function_attr (HirId node_id, Location locus); + StackedContexts<HirId> unsafe_context; Resolver::TypeCheckContext &context; @@ -163,7 +168,6 @@ private: virtual void visit (TuplePatternItemsMultiple &tuple_items) override; virtual void visit (TuplePatternItemsRanged &tuple_items) override; virtual void visit (TuplePattern &pattern) override; - virtual void visit (GroupedPattern &pattern) override; virtual void visit (SlicePattern &pattern) override; virtual void visit (EmptyStmt &stmt) override; virtual void visit (LetStmt &stmt) override; diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc index a189574..3a94699 100644 --- a/gcc/rust/expand/rust-attribute-visitor.cc +++ b/gcc/rust/expand/rust-attribute-visitor.cc @@ -1122,7 +1122,7 @@ AttrVisitor::visit (AST::CallExpr &expr) stmt->accept_vis (*this); - auto final_fragment = expand_macro_fragment_recursive (); + auto final_fragment = expander.take_expanded_fragment (); if (final_fragment.should_expand ()) { // Remove the current expanded invocation @@ -3152,6 +3152,20 @@ AttrVisitor::visit (AST::SlicePattern &pattern) // TODO: quit stripping now? or keep going? } } +void +AttrVisitor::visit (AST::AltPattern &pattern) +{ + // can't strip individual patterns, only sub-patterns + for (auto &alt : pattern.get_alts ()) + { + alt->accept_vis (*this); + + if (alt->is_marked_for_strip ()) + rust_error_at (alt->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} void AttrVisitor::visit (AST::EmptyStmt &) @@ -3421,7 +3435,7 @@ AttrVisitor::visit (AST::BareFunctionType &type) void AttrVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr) { - auto final_fragment = expand_macro_fragment_recursive (); + auto final_fragment = expander.take_expanded_fragment (); if (final_fragment.should_expand () && final_fragment.is_expression_fragment ()) expr = final_fragment.take_expression_fragment (); @@ -3430,7 +3444,7 @@ AttrVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr) void AttrVisitor::maybe_expand_type (std::unique_ptr<AST::Type> &type) { - auto final_fragment = expand_macro_fragment_recursive (); + auto final_fragment = expander.take_expanded_fragment (); if (final_fragment.should_expand () && final_fragment.is_type_fragment ()) type = final_fragment.take_type_fragment (); } diff --git a/gcc/rust/expand/rust-attribute-visitor.h b/gcc/rust/expand/rust-attribute-visitor.h index cbddc16..2d10735 100644 --- a/gcc/rust/expand/rust-attribute-visitor.h +++ b/gcc/rust/expand/rust-attribute-visitor.h @@ -44,39 +44,6 @@ public: void expand_trait_method_decl (AST::TraitMethodDecl &decl); /** - * Expand The current macro fragment recursively until it could not be - * expanded further. - * - * The return value checking works because correctly - * expanded fragment can never be an error (if the fragment can not be - * expanded, a stand-in error fragment will be returned; for fragments that - * could not be further expanded: the fragment prior to the expansion failure - * will be returned). - * - * @return Either the expanded fragment or an empty errored-out fragment - * indicating an expansion failure. - */ - AST::Fragment expand_macro_fragment_recursive () - { - auto fragment = expander.take_expanded_fragment (*this); - unsigned int original_depth = expander.expansion_depth; - auto final_fragment = AST::Fragment::create_error (); - - while (fragment.should_expand ()) - { - final_fragment = std::move (fragment); - expander.expansion_depth++; - // further expand the previously expanded macro fragment - auto new_fragment = expander.take_expanded_fragment (*this); - if (new_fragment.is_error ()) - break; - fragment = std::move (new_fragment); - } - expander.expansion_depth = original_depth; - return final_fragment; - } - - /** * Expand a set of values, erasing them if they are marked for strip, and * replacing them with expanded macro nodes if necessary. * This function is slightly different from `expand_pointer_allow_strip` as @@ -101,8 +68,7 @@ public: // mark for stripping if required value->accept_vis (*this); - // recursively expand the children - auto final_fragment = expand_macro_fragment_recursive (); + auto final_fragment = expander.take_expanded_fragment (); if (final_fragment.should_expand ()) { @@ -292,6 +258,7 @@ public: void visit (AST::TuplePattern &pattern) override; void visit (AST::GroupedPattern &pattern) override; void visit (AST::SlicePattern &pattern) override; + void visit (AST::AltPattern &pattern) override; void visit (AST::EmptyStmt &) override; void visit (AST::LetStmt &stmt) override; diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 1133440..cf90b38 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -29,6 +29,16 @@ namespace Rust { namespace { + +/** + * Shorthand function for creating unique_ptr tokens + */ +static std::unique_ptr<AST::Token> +make_token (const TokenPtr tok) +{ + return std::unique_ptr<AST::Token> (new AST::Token (tok)); +} + std::unique_ptr<AST::Expr> make_string (Location locus, std::string value) { @@ -37,8 +47,64 @@ make_string (Location locus, std::string value) PrimitiveCoreType::CORETYPE_STR, {}, locus)); } -/* Match the end token of a macro given the start delimiter of the macro */ +// TODO: Is this correct? +static AST::Fragment +make_eager_builtin_invocation ( + AST::BuiltinMacro kind, Location locus, AST::DelimTokenTree arguments, + std::vector<std::unique_ptr<AST::MacroInvocation>> &&pending_invocations) +{ + std::string path_str; + + switch (kind) + { + // TODO: Should this be a table lookup? + case AST::BuiltinMacro::Assert: + path_str = "assert"; + break; + case AST::BuiltinMacro::File: + path_str = "file"; + break; + case AST::BuiltinMacro::Line: + path_str = "line"; + break; + case AST::BuiltinMacro::Column: + path_str = "column"; + break; + case AST::BuiltinMacro::IncludeBytes: + path_str = "include_bytes"; + break; + case AST::BuiltinMacro::IncludeStr: + path_str = "include_str"; + break; + case AST::BuiltinMacro::CompileError: + path_str = "compile_error"; + break; + case AST::BuiltinMacro::Concat: + path_str = "concat"; + break; + case AST::BuiltinMacro::Env: + path_str = "env"; + break; + case AST::BuiltinMacro::Cfg: + path_str = "cfg"; + break; + case AST::BuiltinMacro::Include: + path_str = "include"; + break; + } + std::unique_ptr<AST::Expr> node = AST::MacroInvocation::Builtin ( + kind, + AST::MacroInvocData (AST::SimplePath ( + {AST::SimplePathSegment (path_str, locus)}), + std::move (arguments)), + {}, locus, std::move (pending_invocations)); + + return AST::Fragment ({AST::SingleASTNode (std::move (node))}, + arguments.to_token_stream ()); +} + +/* Match the end token of a macro given the start delimiter of the macro */ static inline TokenId macro_end_token (AST::DelimTokenTree &invoc_token_tree, Parser<MacroInvocLexer> &parser) @@ -64,22 +130,7 @@ macro_end_token (AST::DelimTokenTree &invoc_token_tree, return last_token_id; } -/* Expand and extract an expression from the macro */ - -static inline AST::Fragment -try_expand_macro_expression (AST::Expr *expr, MacroExpander *expander) -{ - rust_assert (expander); - - auto attr_visitor = Rust::AttrVisitor (*expander); - auto early_name_resolver = Resolver::EarlyNameResolver (); - expr->accept_vis (early_name_resolver); - expr->accept_vis (attr_visitor); - return expander->take_expanded_fragment (attr_visitor); -} - /* Expand and then extract a string literal from the macro */ - static std::unique_ptr<AST::LiteralExpr> try_extract_string_literal_from_fragment (const Location &parent_locus, std::unique_ptr<AST::Expr> &node) @@ -97,22 +148,6 @@ try_extract_string_literal_from_fragment (const Location &parent_locus, static_cast<AST::LiteralExpr *> (node->clone_expr ().release ())); } -static std::unique_ptr<AST::LiteralExpr> -try_expand_single_string_literal (AST::Expr *input_expr, - MacroExpander *expander) -{ - auto nodes = try_expand_macro_expression (input_expr, expander); - if (nodes.is_error () || nodes.is_expression_fragment ()) - { - rust_error_at (input_expr->get_locus (), - "argument must be a string literal"); - return nullptr; - } - auto expr = nodes.take_expression_fragment (); - return try_extract_string_literal_from_fragment (input_expr->get_locus (), - expr); -} - static std::vector<std::unique_ptr<AST::Expr>> try_expand_many_expr (Parser<MacroInvocLexer> &parser, const TokenId last_token_id, MacroExpander *expander, @@ -140,22 +175,7 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser, auto expr = parser.parse_expr (AST::AttrVec (), restrictions); // something must be so wrong that the expression could not be parsed rust_assert (expr); - auto nodes = try_expand_macro_expression (expr.get (), expander); - if (nodes.is_error ()) - { - // not macro - result.push_back (std::move (expr)); - } - else if (!nodes.is_expression_fragment ()) - { - rust_error_at (expr->get_locus (), "expected expression"); - has_error = true; - return empty_expr; - } - else - { - result.push_back (nodes.take_expression_fragment ()); - } + result.push_back (std::move (expr)); auto next_token = parser.peek_current_token (); if (!parser.skip_token (COMMA) && next_token->get_id () != last_token_id) @@ -199,12 +219,7 @@ parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree, else if (parser.peek_current_token ()->get_id () == last_token_id) rust_error_at (invoc_locus, "macro takes 1 argument"); else - { - // when the expression does not seem to be a string literal, we then try - // to parse/expand it as macro to see if it expands to a string literal - auto expr = parser.parse_expr (); - lit_expr = try_expand_single_string_literal (expr.get (), expander); - } + rust_error_at (invoc_locus, "argument must be a string literal"); parser.skip_token (last_token_id); @@ -276,8 +291,10 @@ MacroBuiltin::file_handler (Location invoc_locus, AST::MacroInvocData &) auto current_file = Session::get_instance ().linemap->location_file (invoc_locus); auto file_str = AST::SingleASTNode (make_string (invoc_locus, current_file)); + auto str_token + = make_token (Token::make_string (invoc_locus, std::move (current_file))); - return AST::Fragment::complete ({file_str}); + return AST::Fragment ({file_str}, std::move (str_token)); } AST::Fragment @@ -286,11 +303,13 @@ MacroBuiltin::column_handler (Location invoc_locus, AST::MacroInvocData &) auto current_column = Session::get_instance ().linemap->location_to_column (invoc_locus); + auto column_tok = make_token ( + Token::make_int (invoc_locus, std::to_string (current_column))); auto column_no = AST::SingleASTNode (std::unique_ptr<AST::Expr> ( new AST::LiteralExpr (std::to_string (current_column), AST::Literal::INT, PrimitiveCoreType::CORETYPE_U32, {}, invoc_locus))); - return AST::Fragment::complete ({column_no}); + return AST::Fragment ({column_no}, std::move (column_tok)); } /* Expand builtin macro include_bytes!("filename"), which includes the contents @@ -316,14 +335,25 @@ MacroBuiltin::include_bytes_handler (Location invoc_locus, /* Is there a more efficient way to do this? */ std::vector<std::unique_ptr<AST::Expr>> elts; + + // We create the tokens for a borrow expression of a byte array, so + // & [ <byte0>, <byte1>, ... ] + std::vector<std::unique_ptr<AST::Token>> toks; + toks.emplace_back (make_token (Token::make (AMP, invoc_locus))); + toks.emplace_back (make_token (Token::make (LEFT_SQUARE, invoc_locus))); + for (uint8_t b : bytes) { elts.emplace_back ( new AST::LiteralExpr (std::string (1, (char) b), AST::Literal::BYTE, PrimitiveCoreType::CORETYPE_U8, {} /* outer_attrs */, invoc_locus)); + toks.emplace_back (make_token (Token::make_byte_char (invoc_locus, b))); + toks.emplace_back (make_token (Token::make (COMMA, invoc_locus))); } + toks.emplace_back (make_token (Token::make (RIGHT_SQUARE, invoc_locus))); + auto elems = std::unique_ptr<AST::ArrayElems> ( new AST::ArrayElemsValues (std::move (elts), invoc_locus)); @@ -334,8 +364,9 @@ MacroBuiltin::include_bytes_handler (Location invoc_locus, new AST::BorrowExpr (std::move (array), false, false, {}, invoc_locus)); auto node = AST::SingleASTNode (std::move (borrow)); - return AST::Fragment::complete ({node}); -} + + return AST::Fragment ({node}, std::move (toks)); +} // namespace Rust /* Expand builtin macro include_str!("filename"), which includes the contents of the given file as a string. The file must be UTF-8 encoded. Yields an @@ -358,11 +389,61 @@ MacroBuiltin::include_str_handler (Location invoc_locus, std::vector<uint8_t> bytes = load_file_bytes (target_filename.c_str ()); - /* FIXME: Enforce that the file contents are valid UTF-8. */ - std::string str ((const char *) &bytes[0], bytes.size ()); + /* FIXME: reuse lexer */ + int expect_single = 0; + for (uint8_t b : bytes) + { + if (expect_single) + { + if ((b & 0xC0) != 0x80) + /* character was truncated, exit with expect_single != 0 */ + break; + expect_single--; + } + else if (b & 0x80) + { + if (b >= 0xF8) + { + /* more than 4 leading 1s */ + expect_single = 1; + break; + } + else if (b >= 0xF0) + { + /* 4 leading 1s */ + expect_single = 3; + } + else if (b >= 0xE0) + { + /* 3 leading 1s */ + expect_single = 2; + } + else if (b >= 0xC0) + { + /* 2 leading 1s */ + expect_single = 1; + } + else + { + /* only 1 leading 1 */ + expect_single = 1; + break; + } + } + } + + std::string str; + if (expect_single) + rust_error_at (invoc_locus, "%s was not a valid utf-8 file", + target_filename.c_str ()); + else + str = std::string ((const char *) &bytes[0], bytes.size ()); auto node = AST::SingleASTNode (make_string (invoc_locus, str)); - return AST::Fragment::complete ({node}); + auto str_tok = make_token (Token::make_string (invoc_locus, std::move (str))); + + // FIXME: Do not return an empty token vector here + return AST::Fragment ({node}, std::move (str_tok)); } /* Expand builtin macro compile_error!("error"), which forces a compile error @@ -383,9 +464,62 @@ MacroBuiltin::compile_error_handler (Location invoc_locus, return AST::Fragment::create_error (); } +static std::vector<std::unique_ptr<AST::MacroInvocation>> +check_for_eager_invocations ( + std::vector<std::unique_ptr<AST::Expr>> &expressions) +{ + std::vector<std::unique_ptr<AST::MacroInvocation>> pending; + + for (auto &expr : expressions) + if (expr->get_ast_kind () == AST::Kind::MACRO_INVOCATION) + pending.emplace_back (std::unique_ptr<AST::MacroInvocation> ( + static_cast<AST::MacroInvocation *> (expr->clone_expr ().release ()))); + + return pending; +} + /* Expand builtin macro concat!(), which joins all the literal parameters into a string with no delimiter. */ +// This is a weird one. We want to do something where, if something cannot be +// expanded yet (i.e. macro invocation?) we return the whole MacroInvocation +// node again but expanded as much as possible. +// Is that possible? How do we do that? +// +// Let's take a few examples: +// +// 1. concat!(1, 2, true); +// 2. concat!(a!(), 2, true); +// 3. concat!(concat!(1, false), 2, true); +// 4. concat!(concat!(1, a!()), 2, true); +// +// 1. We simply want to return the new fragment: "12true" +// 2. We want to return `concat!(a_expanded, 2, true)` as a fragment +// 3. We want to return `concat!(1, false, 2, true)` +// 4. We want to return `concat!(concat!(1, a_expanded), 2, true); +// +// How do we do that? +// +// For each (un)expanded fragment: we check if it is expanded fully +// +// 1. What is expanded fully? +// 2. How to check? +// +// If it is expanded fully and not a literal, then we error out. +// Otherwise we simply emplace it back and keep going. +// +// In the second case, we must mark that this concat invocation still has some +// expansion to do: This allows us to return a `MacroInvocation { ... }` as an +// AST fragment, instead of a completed string. +// +// This means that we must change all the `try_expand_many_*` APIs and so on to +// return some sort of index or way to signify that we might want to reuse some +// bits and pieces of the original token tree. +// +// Now, before that: How do we resolve the names used in a builtin macro +// invocation? +// Do we split the two passes of parsing the token tree and then expanding it? +// Can we do that easily? AST::Fragment MacroBuiltin::concat_handler (Location invoc_locus, AST::MacroInvocData &invoc) { @@ -398,12 +532,25 @@ MacroBuiltin::concat_handler (Location invoc_locus, AST::MacroInvocData &invoc) auto last_token_id = macro_end_token (invoc_token_tree, parser); + auto start = lex.get_offs (); /* NOTE: concat! could accept no argument, so we don't have any checks here */ auto expanded_expr = try_expand_many_expr (parser, last_token_id, invoc.get_expander (), has_error); + auto end = lex.get_offs (); + + auto tokens = lex.get_token_slice (start, end); + + auto pending_invocations = check_for_eager_invocations (expanded_expr); + if (!pending_invocations.empty ()) + return make_eager_builtin_invocation (AST::BuiltinMacro::Concat, + invoc_locus, + invoc.get_delim_tok_tree (), + std::move (pending_invocations)); + for (auto &expr : expanded_expr) { - if (!expr->is_literal ()) + if (!expr->is_literal () + && expr->get_ast_kind () != AST::MACRO_INVOCATION) { has_error = true; rust_error_at (expr->get_locus (), "expected a literal"); @@ -431,12 +578,13 @@ MacroBuiltin::concat_handler (Location invoc_locus, AST::MacroInvocData &invoc) return AST::Fragment::create_error (); auto node = AST::SingleASTNode (make_string (invoc_locus, str)); - return AST::Fragment::complete ({node}); + auto str_tok = make_token (Token::make_string (invoc_locus, std::move (str))); + + return AST::Fragment ({node}, std::move (str_tok)); } /* Expand builtin macro env!(), which inspects an environment variable at compile time. */ - AST::Fragment MacroBuiltin::env_handler (Location invoc_locus, AST::MacroInvocData &invoc) { @@ -449,10 +597,22 @@ MacroBuiltin::env_handler (Location invoc_locus, AST::MacroInvocData &invoc) std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr; bool has_error = false; + auto start = lex.get_offs (); auto expanded_expr = try_expand_many_expr (parser, last_token_id, invoc.get_expander (), has_error); + auto end = lex.get_offs (); + + auto tokens = lex.get_token_slice (start, end); + if (has_error) return AST::Fragment::create_error (); + + auto pending = check_for_eager_invocations (expanded_expr); + if (!pending.empty ()) + return make_eager_builtin_invocation (AST::BuiltinMacro::Env, invoc_locus, + invoc_token_tree, + std::move (pending)); + if (expanded_expr.size () < 1 || expanded_expr.size () > 2) { rust_error_at (invoc_locus, "env! takes 1 or 2 arguments"); @@ -492,7 +652,11 @@ MacroBuiltin::env_handler (Location invoc_locus, AST::MacroInvocData &invoc) } auto node = AST::SingleASTNode (make_string (invoc_locus, env_value)); - return AST::Fragment::complete ({node}); + auto tok + = make_token (Token::make_string (invoc_locus, std::move (env_value))); + + // FIXME: Do not return an empty token vector here + return AST::Fragment ({node}, std::move (tok)); } AST::Fragment @@ -527,8 +691,11 @@ MacroBuiltin::cfg_handler (Location invoc_locus, AST::MacroInvocData &invoc) auto literal_exp = AST::SingleASTNode (std::unique_ptr<AST::Expr> ( new AST::LiteralExpr (result ? "true" : "false", AST::Literal::BOOL, PrimitiveCoreType::CORETYPE_BOOL, {}, invoc_locus))); + auto tok = make_token ( + Token::make (result ? TRUE_LITERAL : FALSE_LITERAL, invoc_locus)); - return AST::Fragment::complete ({literal_exp}); + // FIXME: Do not return an empty token vector here + return AST::Fragment ({literal_exp}, std::move (tok)); } /* Expand builtin macro include!(), which includes a source file at the current @@ -569,7 +736,7 @@ MacroBuiltin::include_handler (Location invoc_locus, AST::MacroInvocData &invoc) bool has_error = !parser.get_errors ().empty (); for (const auto &error : parser.get_errors ()) - error.emit_error (); + error.emit (); if (has_error) { @@ -585,7 +752,19 @@ MacroBuiltin::include_handler (Location invoc_locus, AST::MacroInvocData &invoc) nodes.push_back (node); } - return AST::Fragment::complete (nodes); + // FIXME: This returns an empty vector of tokens and works fine, but is that + // the expected behavior? `include` macros are a bit harder to reason about + // since they include tokens. Furthermore, our lexer has no easy way to return + // a slice of tokens like the MacroInvocLexer. So it gets even harder to + // extrac tokens from here. For now, let's keep it that way and see if it + // eventually breaks, but I don't expect it to cause many issues since the + // list of tokens is only used when a macro invocation mixes eager + // macro invocations and already expanded tokens. Think + // `concat!(a!(), 15, b!())`. We need to be able to expand a!(), expand b!(), + // and then insert the `15` token in between. In the case of `include!()`, we + // only have one argument. So it's either going to be a macro invocation or a + // string literal. + return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); } AST::Fragment @@ -597,8 +776,11 @@ MacroBuiltin::line_handler (Location invoc_locus, AST::MacroInvocData &) auto line_no = AST::SingleASTNode (std::unique_ptr<AST::Expr> ( new AST::LiteralExpr (std::to_string (current_line), AST::Literal::INT, PrimitiveCoreType::CORETYPE_U32, {}, invoc_locus))); + auto tok + = make_token (Token::make_int (invoc_locus, std::to_string (current_line))); - return AST::Fragment::complete ({line_no}); + // FIXME: Do not return an empty token vector here + return AST::Fragment ({line_no}, std::move (tok)); } } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 9c3523e..71aafef 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -111,6 +111,122 @@ MacroExpander::expand_decl_macro (Location invoc_locus, } void +MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc) +{ + if (invoc.get_pending_eager_invocations ().empty ()) + return; + + // We have to basically create a new delimited token tree which contains the + // result of one step of expansion. In the case of builtin macros called with + // other macro invocations, such as `concat!("h", 'a', a!())`, we need to + // expand `a!()` before expanding the concat macro. + // This will, ideally, give us a new token tree containing the various + // existing tokens + the result of the expansion of a!(). + // To do this, we "parse" the given token tree to find anything that "looks + // like a macro invocation". Then, we get the corresponding macro invocation + // from the `pending_eager_invocations` vector and expand it. + // Because the `pending_eager_invocations` vector is created in the same order + // that the DelimTokenTree is parsed, we know that the first macro invocation + // within the DelimTokenTree corresponds to the first element in + // `pending_eager_invocations`. The idea is thus to: + // 1. Find a macro invocation in the token tree, noting the index of the start + // token and of the end token + // 2. Get its associated invocation in `pending_eager_invocations` + // 3. Expand that element + // 4. Get the token tree associated with that AST fragment + // 5. Replace the original tokens corresponding to the invocation with the new + // tokens from the fragment + // pseudo-code: + // + // i = 0; + // for tok in dtt: + // if tok is identifier && tok->next() is !: + // start = index(tok); + // l_delim = tok->next()->next(); + // tok = skip_until_r_delim(); + // end = index(tok); + // + // new_tt = expand_eager_invoc(eagers[i++]); + // old_tt[start..end] = new_tt; + + auto dtt = invoc.get_invoc_data ().get_delim_tok_tree (); + auto stream = dtt.to_token_stream (); + std::vector<std::unique_ptr<AST::TokenTree>> new_stream; + size_t current_pending = 0; + + // we need to create a clone of the delimited token tree as the lexer + // expects ownership of the tokens + std::vector<std::unique_ptr<Rust::AST::Token>> dtt_clone; + for (auto &tok : stream) + dtt_clone.emplace_back (tok->clone_token ()); + + MacroInvocLexer lex (std::move (dtt_clone)); + Parser<MacroInvocLexer> parser (lex); + + // we want to build a substitution map - basically, associating a `start` and + // `end` index for each of the pending macro invocations + std::map<std::pair<size_t, size_t>, std::unique_ptr<AST::MacroInvocation> &> + substitution_map; + + for (size_t i = 0; i < stream.size (); i++) + { + // FIXME: Can't these offsets be figure out when we actually parse the + // pending_eager_invocation in the first place? + auto invocation = parser.parse_macro_invocation ({}); + + // if we've managed to parse a macro invocation, we look at the current + // offset and store them in the substitution map. Otherwise, we skip one + // token and try parsing again + if (invocation) + substitution_map.insert ( + {{i, parser.get_token_source ().get_offs ()}, + invoc.get_pending_eager_invocations ()[current_pending++]}); + else + parser.skip_token (stream[i]->get_id ()); + } + + size_t current_idx = 0; + for (auto kv : substitution_map) + { + auto &to_expand = kv.second; + expand_invoc (*to_expand, false); + + auto fragment = take_expanded_fragment (); + auto &new_tokens = fragment.get_tokens (); + + auto start = kv.first.first; + auto end = kv.first.second; + + // We're now going to re-add the tokens to the invocation's token tree. + // 1. Basically, what we want to do is insert all tokens up until the + // beginning of the macro invocation (start). + // 2. Then, we'll insert all of the tokens resulting from the macro + // expansion: These are in `new_tokens`. + // 3. Finally, we'll do that again from + // the end of macro and go back to 1. + + for (size_t i = current_idx; i < start; i++) + new_stream.emplace_back (stream[i]->clone_token ()); + + for (auto &tok : new_tokens) + new_stream.emplace_back (tok->clone_token ()); + + current_idx = end; + } + + // Once all of that is done, we copy the last remaining tokens from the + // original stream + for (size_t i = current_idx; i < stream.size (); i++) + new_stream.emplace_back (stream[i]->clone_token ()); + + auto new_dtt + = AST::DelimTokenTree (dtt.get_delim_type (), std::move (new_stream)); + + invoc.get_pending_eager_invocations ().clear (); + invoc.get_invoc_data ().set_delim_tok_tree (new_dtt); +} + +void MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) { if (depth_exceeds_recursion_limit ()) @@ -119,6 +235,9 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) return; } + if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) + expand_eager_invocations (invoc); + AST::MacroInvocData &invoc_data = invoc.get_invoc_data (); // ?? @@ -151,6 +270,11 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) if (!ok) return; + // We store the last expanded invocation and macro definition for error + // reporting in case the recursion limit is reached + last_invoc = &invoc; + last_def = rules_def; + if (rules_def->is_builtin ()) fragment = rules_def->get_builtin_transcriber () (invoc.get_locus (), invoc_data); @@ -292,7 +416,7 @@ MacroExpander::expand_crate () // mark for stripping if required item->accept_vis (attr_visitor); - auto fragment = take_expanded_fragment (attr_visitor); + auto fragment = take_expanded_fragment (); if (fragment.should_expand ()) { // Remove the current expanded invocation @@ -711,6 +835,9 @@ static AST::Fragment parse_many (Parser<MacroInvocLexer> &parser, TokenId &delimiter, std::function<AST::SingleASTNode ()> parse_fn) { + auto &lexer = parser.get_token_source (); + auto start = lexer.get_offs (); + std::vector<AST::SingleASTNode> nodes; while (true) { @@ -721,15 +848,16 @@ parse_many (Parser<MacroInvocLexer> &parser, TokenId &delimiter, if (node.is_error ()) { for (auto err : parser.get_errors ()) - err.emit_error (); + err.emit (); return AST::Fragment::create_error (); } nodes.emplace_back (std::move (node)); } + auto end = lexer.get_offs (); - return AST::Fragment::complete (std::move (nodes)); + return AST::Fragment (std::move (nodes), lexer.get_token_slice (start, end)); } /** @@ -838,9 +966,16 @@ transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId &delimiter) static AST::Fragment transcribe_expression (Parser<MacroInvocLexer> &parser) { + auto &lexer = parser.get_token_source (); + auto start = lexer.get_offs (); + auto expr = parser.parse_expr (); + if (expr == nullptr) + return AST::Fragment::create_error (); + + auto end = lexer.get_offs (); - return AST::Fragment::complete ({std::move (expr)}); + return AST::Fragment ({std::move (expr)}, lexer.get_token_slice (start, end)); } /** @@ -851,11 +986,16 @@ transcribe_expression (Parser<MacroInvocLexer> &parser) static AST::Fragment transcribe_type (Parser<MacroInvocLexer> &parser) { + auto &lexer = parser.get_token_source (); + auto start = lexer.get_offs (); + auto type = parser.parse_type (true); for (auto err : parser.get_errors ()) - err.emit_error (); + err.emit (); + + auto end = lexer.get_offs (); - return AST::Fragment::complete ({std::move (type)}); + return AST::Fragment ({std::move (type)}, lexer.get_token_slice (start, end)); } static AST::Fragment diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index bf761c1..9471416 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -231,7 +231,7 @@ struct MacroExpander : cfg (cfg), crate (crate), session (session), sub_stack (SubstitutionScope ()), expanded_fragment (AST::Fragment::create_error ()), - resolver (Resolver::Resolver::get ()), + has_changed_flag (false), resolver (Resolver::Resolver::get ()), mappings (Analysis::Mappings::get ()) {} @@ -240,6 +240,12 @@ struct MacroExpander // Expands all macros in the crate passed in. void expand_crate (); + /** + * Expand the eager invocations contained within a builtin macro invocation. + * Called by `expand_invoc` when expanding builtin invocations. + */ + void expand_eager_invocations (AST::MacroInvocation &invoc); + /* Expands a macro invocation - possibly make both * have similar duck-typed interface and use templates?*/ // should this be public or private? @@ -315,49 +321,44 @@ struct MacroExpander void set_expanded_fragment (AST::Fragment &&fragment) { + if (!fragment.is_error ()) + has_changed_flag = true; + expanded_fragment = std::move (fragment); } - AST::Fragment take_expanded_fragment (AST::ASTVisitor &vis) + AST::Fragment take_expanded_fragment () { - AST::Fragment old_fragment = std::move (expanded_fragment); - auto accumulator = std::vector<AST::SingleASTNode> (); + auto fragment = std::move (expanded_fragment); expanded_fragment = AST::Fragment::create_error (); - auto early_name_resolver = Resolver::EarlyNameResolver (); - - for (auto &node : old_fragment.get_nodes ()) - { - expansion_depth++; - - node.accept_vis (early_name_resolver); - node.accept_vis (vis); - // we'll decide the next move according to the outcome of the macro - // expansion - if (expanded_fragment.is_error ()) - accumulator.push_back (node); // if expansion fails, there might be a - // non-macro expression we need to keep - else - { - // if expansion succeeded, then we need to merge the fragment with - // the contents in the accumulator, so that our final expansion - // result will contain non-macro nodes as it should - auto new_nodes = expanded_fragment.get_nodes (); - std::move (new_nodes.begin (), new_nodes.end (), - std::back_inserter (accumulator)); - expanded_fragment = AST::Fragment::complete (accumulator); - } - expansion_depth--; - } - - return old_fragment; + + return fragment; } + /** + * Has the MacroExpander expanded a macro since its state was last reset? + */ + bool has_changed () const { return has_changed_flag; } + + /** + * Reset the expander's "changed" state. This function should be executed at + * each iteration in a fixed point loop + */ + void reset_changed_state () { has_changed_flag = false; } + + AST::MacroRulesDefinition *get_last_definition () { return last_def; } + AST::MacroInvocation *get_last_invocation () { return last_invoc; } + private: AST::Crate &crate; Session &session; SubstitutionScope sub_stack; std::vector<ContextType> context; AST::Fragment expanded_fragment; + bool has_changed_flag; + + AST::MacroRulesDefinition *last_def; + AST::MacroInvocation *last_invoc; public: Resolver::Resolver *resolver; diff --git a/gcc/rust/expand/rust-macro-invoc-lexer.cc b/gcc/rust/expand/rust-macro-invoc-lexer.cc index 8a43d29..321f0f9 100644 --- a/gcc/rust/expand/rust-macro-invoc-lexer.cc +++ b/gcc/rust/expand/rust-macro-invoc-lexer.cc @@ -26,4 +26,18 @@ MacroInvocLexer::split_current_token (TokenId new_left __attribute__ ((unused)), // FIXME gcc_unreachable (); } + +std::vector<std::unique_ptr<AST::Token>> +MacroInvocLexer::get_token_slice (size_t start_idx, size_t end_idx) const +{ + std::vector<std::unique_ptr<AST::Token>> slice; + + rust_assert (end_idx < token_stream.size ()); + + for (size_t i = start_idx; i < end_idx; i++) + slice.emplace_back (token_stream[i]->clone_token ()); + + return slice; +} + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-invoc-lexer.h b/gcc/rust/expand/rust-macro-invoc-lexer.h index a0d3016..0923c18 100644 --- a/gcc/rust/expand/rust-macro-invoc-lexer.h +++ b/gcc/rust/expand/rust-macro-invoc-lexer.h @@ -55,6 +55,9 @@ public: size_t get_offs () const { return offs; } + std::vector<std::unique_ptr<AST::Token>> + get_token_slice (size_t start_idx, size_t end_idx) const; + private: size_t offs; std::vector<std::unique_ptr<AST::Token>> token_stream; diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 3379572..5d7b5d2 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -461,6 +461,9 @@ ASTLoweringBase::visit (AST::GroupedPattern &) void ASTLoweringBase::visit (AST::SlicePattern &) {} +void +ASTLoweringBase::visit (AST::AltPattern &) +{} // rust-stmt.h void diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 1af44aa..85343aa 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -231,6 +231,7 @@ public: virtual void visit (AST::TuplePattern &pattern); virtual void visit (AST::GroupedPattern &pattern); virtual void visit (AST::SlicePattern &pattern); + virtual void visit (AST::AltPattern &pattern); // rust-stmt.h virtual void visit (AST::EmptyStmt &stmt); diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index df4ba9d..50c2eae 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index 30a1882..1961c74 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -243,5 +243,40 @@ ASTLoweringPattern::visit (AST::RangePattern &pattern) std::move (upper_bound), pattern.get_locus ()); } +void +ASTLoweringPattern::visit (AST::GroupedPattern &pattern) +{ + pattern.get_pattern_in_parens ()->accept_vis (*this); +} + +void +ASTLoweringPattern::visit (AST::ReferencePattern &pattern) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Pattern *inner + = ASTLoweringPattern::translate (pattern.get_referenced_pattern ().get ()); + + translated + = new HIR::ReferencePattern (mapping, std::unique_ptr<HIR::Pattern> (inner), + pattern.get_is_mut () ? Mutability::Mut + : Mutability::Imm, + pattern.get_locus ()); + + if (pattern.is_double_reference ()) + { + Analysis::NodeMapping mapping2 (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::ReferencePattern (mapping2, + std::unique_ptr<HIR::Pattern> (translated), + Mutability::Imm, pattern.get_locus ()); + } +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-pattern.h b/gcc/rust/hir/rust-ast-lower-pattern.h index 8b191d5..2d175a2 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.h +++ b/gcc/rust/hir/rust-ast-lower-pattern.h @@ -39,6 +39,8 @@ public: void visit (AST::TuplePattern &pattern) override; void visit (AST::LiteralPattern &pattern) override; void visit (AST::RangePattern &pattern) override; + void visit (AST::GroupedPattern &pattern) override; + void visit (AST::ReferencePattern &pattern) override; private: ASTLoweringPattern (); diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index 92a14f4..9ea22b0 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index 875e1dd..10720c4 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -457,9 +457,6 @@ void Dump::visit (TuplePattern &) {} void -Dump::visit (GroupedPattern &) -{} -void Dump::visit (SlicePattern &) {} diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index 8715a95..b66e6b1 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -163,7 +163,6 @@ private: virtual void visit (TuplePatternItemsMultiple &) override; virtual void visit (TuplePatternItemsRanged &) override; virtual void visit (TuplePattern &) override; - virtual void visit (GroupedPattern &) override; virtual void visit (SlicePattern &) override; virtual void visit (EmptyStmt &) override; diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index cc88442..bf10351 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -23,7 +23,7 @@ #include "rust-ast-full-decls.h" #include "rust-hir.h" #include "rust-hir-path.h" -#include "operator.h" +#include "rust-operators.h" namespace Rust { namespace HIR { diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index 7870a54..30adda6 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -206,7 +206,6 @@ class TuplePatternItems; class TuplePatternItemsMultiple; class TuplePatternItemsRanged; class TuplePattern; -class GroupedPattern; class SlicePattern; // rust-type.h diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index f7bf1f8..03e1f71 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -1226,6 +1226,11 @@ public: SelfParam &get_self_param () { return self; } + std::string get_impl_item_name () const override final + { + return get_function_name (); + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1345,6 +1350,11 @@ public: return get_mappings (); }; + std::string get_impl_item_name () const override final + { + return get_new_type_name (); + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2116,7 +2126,7 @@ public: Expr *get_expr () { return const_expr.get (); } - std::string get_identifier () { return identifier; } + std::string get_identifier () const { return identifier; } Analysis::NodeMapping get_impl_mappings () const override { @@ -2130,6 +2140,11 @@ public: ItemKind get_item_kind () const override { return ItemKind::Constant; } + std::string get_impl_item_name () const override final + { + return get_identifier (); + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 17eedb8..740de93 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -105,9 +105,11 @@ public: std::string as_string () const; - Identifier get_identifier () const { return identifier; } + Identifier &get_identifier () { return identifier; } + const Identifier &get_identifier () const { return identifier; } std::unique_ptr<Type> &get_type () { return type; } + const std::unique_ptr<Type> &get_type () const { return type; } Location get_locus () const { return locus; } }; diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 80fa9b7..1b08ab8 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -424,7 +424,6 @@ protected: // HIR node for pattern based on dereferencing the pointers given class ReferencePattern : public Pattern { - bool has_two_amps; Mutability mut; std::unique_ptr<Pattern> pattern; Location locus; @@ -435,16 +434,15 @@ public: ReferencePattern (Analysis::NodeMapping mappings, std::unique_ptr<Pattern> pattern, Mutability reference_mut, - bool ref_has_two_amps, Location locus) - : has_two_amps (ref_has_two_amps), mut (reference_mut), - pattern (std::move (pattern)), locus (locus), mappings (mappings) + Location locus) + : mut (reference_mut), pattern (std::move (pattern)), locus (locus), + mappings (mappings) {} // Copy constructor requires clone ReferencePattern (ReferencePattern const &other) - : has_two_amps (other.has_two_amps), mut (other.mut), - pattern (other.pattern->clone_pattern ()), locus (other.locus), - mappings (other.mappings) + : mut (other.mut), pattern (other.pattern->clone_pattern ()), + locus (other.locus), mappings (other.mappings) {} // Overload assignment operator to clone @@ -452,7 +450,6 @@ public: { pattern = other.pattern->clone_pattern (); mut = other.mut; - has_two_amps = other.has_two_amps; locus = other.locus; mappings = other.mappings; @@ -1145,6 +1142,24 @@ public: return TuplePatternItemType::RANGED; } + std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () + { + return lower_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () const + { + return lower_patterns; + } + + std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () + { + return upper_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () const + { + return upper_patterns; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1215,69 +1230,6 @@ protected: } }; -// HIR node representing a pattern in parentheses, used to control precedence -class GroupedPattern : public Pattern -{ - std::unique_ptr<Pattern> pattern_in_parens; - Location locus; - Analysis::NodeMapping mappings; - -public: - std::string as_string () const override - { - return "(" + pattern_in_parens->as_string () + ")"; - } - - GroupedPattern (Analysis::NodeMapping mappings, - std::unique_ptr<Pattern> pattern_in_parens, Location locus) - : pattern_in_parens (std::move (pattern_in_parens)), locus (locus), - mappings (mappings) - {} - - // Copy constructor uses clone - GroupedPattern (GroupedPattern const &other) - : pattern_in_parens (other.pattern_in_parens->clone_pattern ()), - locus (other.locus), mappings (other.mappings) - {} - - // Overload assignment operator to clone - GroupedPattern &operator= (GroupedPattern const &other) - { - pattern_in_parens = other.pattern_in_parens->clone_pattern (); - locus = other.locus; - mappings = other.mappings; - - return *this; - } - - // default move semantics - GroupedPattern (GroupedPattern &&other) = default; - GroupedPattern &operator= (GroupedPattern &&other) = default; - - Location get_locus () const override { return locus; } - - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRPatternVisitor &vis) override; - - Analysis::NodeMapping get_pattern_mappings () const override final - { - return mappings; - } - - PatternType get_pattern_type () const override final - { - return PatternType::GROUPED; - } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - GroupedPattern *clone_pattern_impl () const override - { - return new GroupedPattern (*this); - } -}; - // HIR node representing patterns that can match slices and arrays class SlicePattern : public Pattern { diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index ba6cad7..a635f90 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -138,7 +138,6 @@ public: virtual void visit (TuplePatternItemsMultiple &tuple_items) = 0; virtual void visit (TuplePatternItemsRanged &tuple_items) = 0; virtual void visit (TuplePattern &pattern) = 0; - virtual void visit (GroupedPattern &pattern) = 0; virtual void visit (SlicePattern &pattern) = 0; virtual void visit (EmptyStmt &stmt) = 0; virtual void visit (LetStmt &stmt) = 0; @@ -290,7 +289,6 @@ public: virtual void visit (TuplePatternItemsMultiple &) override {} virtual void visit (TuplePatternItemsRanged &) override {} virtual void visit (TuplePattern &) override {} - virtual void visit (GroupedPattern &) override {} virtual void visit (SlicePattern &) override {} virtual void visit (EmptyStmt &) override {} @@ -470,7 +468,6 @@ public: class HIRPatternVisitor { public: - virtual void visit (GroupedPattern &) = 0; virtual void visit (IdentifierPattern &) = 0; virtual void visit (LiteralPattern &) = 0; virtual void visit (PathInExpression &) = 0; diff --git a/gcc/rust/hir/tree/rust-hir-full-test.cc b/gcc/rust/hir/tree/rust-hir.cc index 230b7f7..0ddb841 100644 --- a/gcc/rust/hir/tree/rust-hir-full-test.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2583,11 +2583,6 @@ ReferencePattern::as_string () const { std::string str ("&"); - if (has_two_amps) - { - str += "&"; - } - if (is_mut ()) { str += "mut "; @@ -4477,12 +4472,6 @@ TuplePattern::accept_vis (HIRFullVisitor &vis) } void -GroupedPattern::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - -void SlicePattern::accept_vis (HIRFullVisitor &vis) { vis.visit (*this); @@ -4609,12 +4598,6 @@ EmptyStmt::accept_vis (HIRStmtVisitor &vis) } void -GroupedPattern::accept_vis (HIRPatternVisitor &vis) -{ - vis.visit (*this); -} - -void WildcardPattern::accept_vis (HIRPatternVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index 314aafb..28f1f21 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -839,6 +839,8 @@ public: virtual ImplItemType get_impl_item_type () const = 0; + virtual std::string get_impl_item_name () const = 0; + protected: // Clone function implementation as pure virtual method virtual ImplItem *clone_inherent_impl_item_impl () const = 0; diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc index ac7ced5..9967cec 100644 --- a/gcc/rust/lex/rust-lex.cc +++ b/gcc/rust/lex/rust-lex.cc @@ -447,6 +447,7 @@ Lexer::build_token () // match arm arrow skip_input (); current_column += 2; + loc += 1; return Token::make (MATCH_ARROW, loc); } @@ -455,6 +456,7 @@ Lexer::build_token () // equality operator skip_input (); current_column += 2; + loc += 1; return Token::make (EQUAL_EQUAL, loc); } @@ -473,6 +475,7 @@ Lexer::build_token () // return type specifier skip_input (); current_column += 2; + loc += 1; return Token::make (RETURN_TYPE, loc); } @@ -481,6 +484,7 @@ Lexer::build_token () // minus-assign skip_input (); current_column += 2; + loc += 1; return Token::make (MINUS_EQ, loc); } @@ -496,6 +500,7 @@ Lexer::build_token () // add-assign skip_input (); current_column += 2; + loc += 1; return Token::make (PLUS_EQ, loc); } @@ -517,6 +522,7 @@ Lexer::build_token () // multiplication-assign skip_input (); current_column += 2; + loc += 1; return Token::make (ASTERISK_EQ, loc); } @@ -535,6 +541,7 @@ Lexer::build_token () // division-assign skip_input (); current_column += 2; + loc += 1; return Token::make (DIV_EQ, loc); } @@ -602,6 +609,8 @@ Lexer::build_token () start_line (current_line, max_column_hint); str.shrink_to_fit (); + + loc += str.size () - 1; if (is_inner) return Token::make_inner_doc_comment (loc, std::move (str)); else @@ -756,6 +765,8 @@ Lexer::build_token () } str.shrink_to_fit (); + + loc += str.size () - 1; if (is_inner) return Token::make_inner_doc_comment (loc, std::move (str)); else @@ -773,6 +784,7 @@ Lexer::build_token () // modulo-assign skip_input (); current_column += 2; + loc += 1; return Token::make (PERCENT_EQ, loc); } @@ -788,6 +800,7 @@ Lexer::build_token () // xor-assign? skip_input (); current_column += 2; + loc += 1; return Token::make (CARET_EQ, loc); } @@ -805,6 +818,7 @@ Lexer::build_token () // left-shift assign skip_input (1); current_column += 3; + loc += 2; return Token::make (LEFT_SHIFT_EQ, loc); } @@ -813,6 +827,7 @@ Lexer::build_token () // left-shift skip_input (); current_column += 2; + loc += 1; return Token::make (LEFT_SHIFT, loc); } @@ -822,6 +837,7 @@ Lexer::build_token () // smaller than or equal to skip_input (); current_column += 2; + loc += 1; return Token::make (LESS_OR_EQUAL, loc); } @@ -840,6 +856,7 @@ Lexer::build_token () // right-shift-assign skip_input (1); current_column += 3; + loc += 2; return Token::make (RIGHT_SHIFT_EQ, loc); } @@ -848,6 +865,7 @@ Lexer::build_token () // right-shift skip_input (); current_column += 2; + loc += 1; return Token::make (RIGHT_SHIFT, loc); } @@ -857,6 +875,7 @@ Lexer::build_token () // larger than or equal to skip_input (); current_column += 2; + loc += 1; return Token::make (GREATER_OR_EQUAL, loc); } @@ -872,6 +891,7 @@ Lexer::build_token () // scope resolution :: skip_input (); current_column += 2; + loc += 1; return Token::make (SCOPE_RESOLUTION, loc); } @@ -888,6 +908,7 @@ Lexer::build_token () // not equal boolean operator skip_input (); current_column += 2; + loc += 1; return Token::make (NOT_EQUAL, loc); } @@ -937,6 +958,7 @@ Lexer::build_token () // bitwise or-assign? skip_input (); current_column += 2; + loc += 1; return Token::make (PIPE_EQ, loc); } @@ -945,6 +967,7 @@ Lexer::build_token () // logical or skip_input (); current_column += 2; + loc += 1; return Token::make (OR, loc); } @@ -961,6 +984,7 @@ Lexer::build_token () // bitwise and-assign? skip_input (); current_column += 2; + loc += 1; return Token::make (AMP_EQ, loc); } @@ -969,6 +993,7 @@ Lexer::build_token () // logical and skip_input (); current_column += 2; + loc += 1; return Token::make (LOGICAL_AND, loc); } @@ -987,6 +1012,7 @@ Lexer::build_token () // ellipsis skip_input (1); current_column += 3; + loc += 2; return Token::make (ELLIPSIS, loc); } @@ -995,6 +1021,7 @@ Lexer::build_token () // ..= skip_input (1); current_column += 3; + loc += 2; return Token::make (DOT_DOT_EQ, loc); } @@ -1003,6 +1030,7 @@ Lexer::build_token () // .. skip_input (); current_column += 2; + loc += 1; return Token::make (DOT_DOT, loc); } @@ -1717,6 +1745,8 @@ Lexer::parse_byte_char (Location loc) current_column += length; + loc += length - 1; + return Token::make_byte_char (loc, byte_char); } @@ -1781,6 +1811,7 @@ Lexer::parse_byte_string (Location loc) } str.shrink_to_fit (); + loc += str.size () - 1; return Token::make_byte_string (loc, std::move (str)); } @@ -1861,6 +1892,8 @@ Lexer::parse_raw_byte_string (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_byte_string (loc, std::move (str)); @@ -1912,6 +1945,7 @@ Lexer::parse_raw_identifier (Location loc) else { str.shrink_to_fit (); + loc += length - 1; return Token::make_identifier (loc, std::move (str)); } @@ -2009,6 +2043,8 @@ Lexer::parse_string (Location loc) } str.shrink_to_fit (); + loc += length - 1; + return Token::make_string (loc, std::move (str)); } @@ -2043,6 +2079,8 @@ Lexer::parse_identifier_or_keyword (Location loc) str.shrink_to_fit (); + loc += length - 1; + TokenId keyword = classify_keyword (str); if (keyword == IDENTIFIER) return Token::make_identifier (loc, std::move (str)); @@ -2120,6 +2158,8 @@ Lexer::parse_raw_string (Location loc, int initial_hash_count) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_string (loc, std::move (str)); @@ -2183,6 +2223,9 @@ Lexer::parse_non_decimal_int_literal (Location loc, IsDigitFunc is_digit_func, : "<insert unknown base>"))); return nullptr; } + + loc += length - 1; + return Token::make_int (loc, std::move (existent_str), type_hint); } @@ -2275,6 +2318,8 @@ Lexer::parse_decimal_int_or_float (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_float (loc, std::move (str), type_hint); } @@ -2295,6 +2340,8 @@ Lexer::parse_decimal_int_or_float (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_float (loc, std::move (str), CORETYPE_UNKNOWN); } @@ -2324,6 +2371,8 @@ Lexer::parse_decimal_int_or_float (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_float (loc, std::move (str), type_hint); } @@ -2345,6 +2394,8 @@ Lexer::parse_decimal_int_or_float (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_int (loc, std::move (str), type_hint); } @@ -2382,6 +2433,8 @@ Lexer::parse_char_or_lifetime (Location loc) current_column += length; + loc += length - 1; + return Token::make_char (loc, current_char32); } else @@ -2399,6 +2452,8 @@ Lexer::parse_char_or_lifetime (Location loc) // TODO fix due to different widths of utf-8 chars? current_column += 3; + loc += 2; + return Token::make_char (loc, current_char32); } else if (ISDIGIT (current_char32.value) || ISALPHA (current_char32.value) @@ -2421,6 +2476,8 @@ Lexer::parse_char_or_lifetime (Location loc) current_column += length; + loc += length - 1; + str.shrink_to_fit (); return Token::make_lifetime (loc, std::move (str)); } diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h index 2dd60b3..5042471 100644 --- a/gcc/rust/lex/rust-lex.h +++ b/gcc/rust/lex/rust-lex.h @@ -38,13 +38,37 @@ private: fclose (file); } + static bool allowed_filetype (const struct stat &statbuf) + { + // The file could be either + // - a regular file + // - a char device (/dev/null...) + return S_ISREG (statbuf.st_mode) || S_ISCHR (statbuf.st_mode); + } + public: RAIIFile (const char *filename) : filename (filename) { if (strcmp (filename, "-") == 0) - file = stdin; + { + file = stdin; + } else - file = fopen (filename, "r"); + { + struct stat statbuf; + if (!(file = fopen (filename, "r"))) + { + return; + } + + if (-1 == fstat (fileno (file), &statbuf) + || !allowed_filetype (statbuf)) + { + fclose (file); + file = nullptr; + errno = EISDIR; + } + } } /** diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index 18f1afa..0fc55a2 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -171,7 +171,7 @@ enum PrimitiveCoreType RS_TOKEN_KEYWORD (IN, "in") \ RS_TOKEN_KEYWORD (LET, "let") \ RS_TOKEN_KEYWORD (LOOP, "loop") \ - RS_TOKEN_KEYWORD (MACRO, "macro") /* unused */ \ + RS_TOKEN_KEYWORD (MACRO, "macro") \ RS_TOKEN_KEYWORD (MATCH_TOK, "match") \ RS_TOKEN_KEYWORD (MOD, "mod") \ RS_TOKEN_KEYWORD (MOVE, "move") \ diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index cbd40ef..db32803d 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -444,7 +444,7 @@ Parser<ManagedTokenSource>::parse_crate () // emit all errors for (const auto &error : error_table) - error.emit_error (); + error.emit (); return std::unique_ptr<AST::Crate> ( new AST::Crate (std::move (items), std::move (inner_attrs))); @@ -1032,11 +1032,6 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement) // parse outer attributes for item AST::AttrVec outer_attrs = parse_outer_attributes (); - - // TODO: decide how to deal with VisItem vs MacroItem dichotomy - /* best current solution: catch all keywords that would imply a VisItem in a - * switch and have MacroItem as a last resort */ - const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) @@ -1064,6 +1059,7 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement) case STATIC_TOK: case TRAIT: case IMPL: + case MACRO: /* TODO: implement union keyword but not really because of * context-dependence crappy hack way to parse a union written below to * separate it from the good code. */ @@ -1078,7 +1074,7 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement) case CRATE: case DOLLAR_SIGN: // almost certainly macro invocation semi - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); break; // crappy hack to do union "keyword" case IDENTIFIER: @@ -1092,19 +1088,18 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement) else if (t->get_str () == "macro_rules") { // macro_rules! macro item - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_rules_def (std::move (outer_attrs)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION || lexer.peek_token (1)->get_id () == EXCLAM) { /* path (probably) or macro invocation, so probably a macro invocation * semi */ - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); } gcc_fallthrough (); default: // otherwise unrecognised - // return parse_macro_item(std::move(outer_attrs)); add_error (Error (t->get_locus (), "unrecognised token %qs for start of %s", t->get_token_description (), @@ -1335,6 +1330,8 @@ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs) lexer.skip_token (1); // TODO: is this right thing to do? return nullptr; } + case MACRO: + return parse_decl_macro_def (std::move (vis), std::move (outer_attrs)); default: // otherwise vis item clearly doesn't exist, which is not an error // has a catch-all post-switch return to allow other breaks to occur @@ -1343,42 +1340,6 @@ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs) return nullptr; } -// Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition). -template <typename ManagedTokenSource> -std::unique_ptr<AST::MacroItem> -Parser<ManagedTokenSource>::parse_macro_item (AST::AttrVec outer_attrs) -{ - const_TokenPtr t = lexer.peek_token (); - - /* dodgy way of detecting macro due to weird context-dependence thing. - * probably can be improved */ - // TODO: ensure that string compare works properly - if (t->get_id () == IDENTIFIER && t->get_str () == "macro_rules") - { - return parse_macro_rules_def (std::move (outer_attrs)); - } - else - { - // DEBUG: TODO: remove - rust_debug ( - "DEBUG - parse_macro_item called and token is not macro_rules"); - if (t->get_id () == IDENTIFIER) - { - rust_debug ("just add to last error: token is not macro_rules and is " - "instead '%s'", - t->get_str ().c_str ()); - } - else - { - rust_debug ("just add to last error: token is not macro_rules and is " - "not an identifier either - it is '%s'", - t->get_token_description ()); - } - - return parse_macro_invocation_semi (std::move (outer_attrs)); - } -} - // Parses a macro rules definition syntax extension whatever thing. template <typename ManagedTokenSource> std::unique_ptr<AST::MacroRulesDefinition> @@ -1512,16 +1473,16 @@ Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs) { // as this is the end, allow recovery (probably) - may change return std::unique_ptr<AST::MacroRulesDefinition> ( - new AST::MacroRulesDefinition ( + AST::MacroRulesDefinition::mbe ( std::move (rule_name), delim_type, std::move (macro_rules), std::move (outer_attrs), macro_locus)); } } return std::unique_ptr<AST::MacroRulesDefinition> ( - new AST::MacroRulesDefinition (std::move (rule_name), delim_type, - std::move (macro_rules), - std::move (outer_attrs), macro_locus)); + AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type, + std::move (macro_rules), + std::move (outer_attrs), macro_locus)); } else { @@ -1541,6 +1502,165 @@ Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs) } } +// Parses a declarative macro 2.0 definition. +template <typename ManagedTokenSource> +std::unique_ptr<AST::MacroRulesDefinition> +Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis, + AST::AttrVec outer_attrs) +{ + // ensure that first token is identifier saying "macro" + const_TokenPtr t = lexer.peek_token (); + if (t->get_id () != MACRO) + { + Error error ( + t->get_locus (), + "declarative macro definition does not start with %<macro%>"); + add_error (std::move (error)); + + // skip after somewhere? + return nullptr; + } + lexer.skip_token (); + Location macro_locus = t->get_locus (); + + // parse macro name + const_TokenPtr ident_tok = expect_token (IDENTIFIER); + if (ident_tok == nullptr) + { + return nullptr; + } + Identifier rule_name = ident_tok->get_str (); + + t = lexer.peek_token (); + if (t->get_id () == LEFT_PAREN) + { + // single definiton of macro rule + // e.g. `macro foo($e:expr) {}` + + // parse macro matcher + Location locus = lexer.peek_token ()->get_locus (); + AST::MacroMatcher matcher = parse_macro_matcher (); + if (matcher.is_error ()) + return nullptr; + + // check delimiter of macro matcher + if (matcher.get_delim_type () != AST::DelimType::PARENS) + { + Error error (locus, "only parenthesis can be used for a macro " + "matcher in declarative macro definition"); + add_error (std::move (error)); + return nullptr; + } + + Location transcriber_loc = lexer.peek_token ()->get_locus (); + AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree (); + AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc); + + if (transcriber.get_token_tree ().get_delim_type () + != AST::DelimType::CURLY) + { + Error error (transcriber_loc, + "only braces can be used for a macro transcriber " + "in declarative macro definition"); + add_error (std::move (error)); + return nullptr; + } + + AST::MacroRule macro_rule + = AST::MacroRule (std::move (matcher), std::move (transcriber), locus); + std::vector<AST::MacroRule> macro_rules; + macro_rules.push_back (macro_rule); + + return std::unique_ptr<AST::MacroRulesDefinition> ( + AST::MacroRulesDefinition::decl_macro (std::move (rule_name), + macro_rules, + std::move (outer_attrs), + macro_locus, vis)); + } + else if (t->get_id () == LEFT_CURLY) + { + // multiple definitions of macro rule separated by comma + // e.g. `macro foo { () => {}, ($e:expr) => {}, }` + + // parse left curly + const_TokenPtr left_curly = expect_token (LEFT_CURLY); + if (left_curly == nullptr) + { + return nullptr; + } + + // parse actual macro rules + std::vector<AST::MacroRule> macro_rules; + + // must be at least one macro rule, so parse it + AST::MacroRule initial_rule = parse_macro_rule (); + if (initial_rule.is_error ()) + { + Error error ( + lexer.peek_token ()->get_locus (), + "required first macro rule in declarative macro definition " + "could not be parsed"); + add_error (std::move (error)); + + // skip after somewhere? + return nullptr; + } + macro_rules.push_back (std::move (initial_rule)); + + t = lexer.peek_token (); + // parse macro rules + while (t->get_id () == COMMA) + { + // skip comma + lexer.skip_token (); + + // don't parse if end of macro rules + if (token_id_matches_delims (lexer.peek_token ()->get_id (), + AST::CURLY)) + { + break; + } + + // try to parse next rule + AST::MacroRule rule = parse_macro_rule (); + if (rule.is_error ()) + { + Error error ( + lexer.peek_token ()->get_locus (), + "failed to parse macro rule in declarative macro definition"); + add_error (std::move (error)); + + return nullptr; + } + + macro_rules.push_back (std::move (rule)); + + t = lexer.peek_token (); + } + + // parse right curly + const_TokenPtr right_curly = expect_token (RIGHT_CURLY); + if (right_curly == nullptr) + { + return nullptr; + } + + return std::unique_ptr<AST::MacroRulesDefinition> ( + AST::MacroRulesDefinition::decl_macro (std::move (rule_name), + std::move (macro_rules), + std::move (outer_attrs), + macro_locus, vis)); + } + else + { + add_error (Error (t->get_locus (), + "unexpected token %qs - expecting delimiters " + "(for a declarative macro definiton)", + t->get_token_description ())); + return nullptr; + } +} + // Parses a semi-coloned (except for full block) macro invocation item. template <typename ManagedTokenSource> std::unique_ptr<AST::MacroInvocation> @@ -1632,10 +1752,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi ( { // as this is the end, allow recovery (probably) - may change - return std::unique_ptr<AST::MacroInvocation> ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), macro_locus, - true)); + return AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), + macro_locus, true); } } @@ -1644,9 +1763,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi ( t->get_token_description (), lexer.peek_token ()->get_token_description ()); - return std::unique_ptr<AST::MacroInvocation> ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), macro_locus, true)); + return AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), + macro_locus, true); } else { @@ -1694,10 +1813,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs) Location macro_locus = macro_path.get_locus (); - return std::unique_ptr<AST::MacroInvocation> ( - new AST::MacroInvocation (AST::MacroInvocData (std::move (macro_path), - std::move (delim_tok_tree)), - std::move (outer_attrs), macro_locus)); + return AST::MacroInvocation::Regular ( + AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)), + std::move (outer_attrs), macro_locus); } // Parses a macro rule definition - does not parse semicolons. @@ -6004,6 +6122,7 @@ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) case STATIC_TOK: case TRAIT: case IMPL: + case MACRO: /* TODO: implement union keyword but not really because of * context-dependence crappy hack way to parse a union written below to * separate it from the good code. */ @@ -6012,14 +6131,22 @@ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) /* if any of these (should be all possible VisItem prefixes), parse a * VisItem can't parse item because would require reparsing outer * attributes */ - return parse_vis_item (std::move (outer_attrs)); + // may also be unsafe block + if (lexer.peek_token (1)->get_id () == LEFT_CURLY) + { + return parse_expr_stmt (std::move (outer_attrs), restrictions); + } + else + { + return parse_vis_item (std::move (outer_attrs)); + } break; case SUPER: case SELF: case CRATE: case DOLLAR_SIGN: // almost certainly macro invocation semi - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); break; // crappy hack to do union "keyword" case IDENTIFIER: @@ -6032,7 +6159,7 @@ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) else if (t->get_str () == "macro_rules") { // macro_rules! macro item - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_rules_def (std::move (outer_attrs)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION || lexer.peek_token (1)->get_id () == EXCLAM) @@ -6040,7 +6167,7 @@ Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) // FIXME: ensure doesn't take any expressions by mistake /* path (probably) or macro invocation, so probably a macro * invocation semi */ - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); } gcc_fallthrough (); // TODO: find out how to disable gcc "implicit fallthrough" warning @@ -6190,7 +6317,9 @@ Parser<ManagedTokenSource>::parse_generic_arg () // could either have a valid type or a macro (FIXME: anything else?). So // we need one bit of lookahead to differentiate if this is really auto next_tok = lexer.peek_token (1); - if (next_tok->get_id () == EXCLAM) + if (next_tok->get_id () == LEFT_ANGLE + || next_tok->get_id () == SCOPE_RESOLUTION + || next_tok->get_id () == EXCLAM) { auto type = parse_type (); if (type) @@ -6198,6 +6327,23 @@ Parser<ManagedTokenSource>::parse_generic_arg () else return AST::GenericArg::create_error (); } + else if (next_tok->get_id () == COLON) + { + lexer.skip_token (); // skip ident + lexer.skip_token (); // skip colon + + auto tok = lexer.peek_token (); + std::vector<std::unique_ptr<AST::TypeParamBound>> bounds + = parse_type_param_bounds (); + + auto type = std::unique_ptr<AST::TraitObjectType> ( + new AST::TraitObjectType (std::move (bounds), tok->get_locus (), + false)); + if (type) + return AST::GenericArg::create_type (std::move (type)); + else + return AST::GenericArg::create_error (); + } lexer.skip_token (); return AST::GenericArg::create_ambiguous (tok->get_str (), tok->get_locus ()); @@ -7050,18 +7196,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, } } case UNSAFE: { - /* FIXME: are there any expressions without blocks that can have - * unsafe as their first token? Or is unsafe the only one? */ - // safe side for now - if (lexer.peek_token (1)->get_id () == LEFT_CURLY) - { - return parse_expr_stmt_with_block (std::move (outer_attrs)); - } - else - { - return parse_expr_stmt_without_block (std::move (outer_attrs), - restrictions); - } + // unsafe block + // https://doc.rust-lang.org/reference/unsafe-keyword.html + return parse_expr_stmt_with_block (std::move (outer_attrs)); } default: // not a parse expr with block, so must be expr without block @@ -7454,6 +7591,7 @@ Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs) case PIPE: // actually may have parameters lexer.skip_token (); + t = lexer.peek_token (); while (t->get_id () != PIPE) { @@ -7470,6 +7608,7 @@ Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs) if (lexer.peek_token ()->get_id () != COMMA) { + lexer.skip_token (); // not an error but means param list is done break; } @@ -9101,6 +9240,7 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) // raw pointer type return parse_raw_pointer_type (); case AMP: // does this also include AMP_AMP? + case LOGICAL_AND: // reference type return parse_reference_type (); case LIFETIME: { @@ -9170,11 +9310,10 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) AST::DelimTokenTree tok_tree = parse_delim_token_tree (); - return std::unique_ptr<AST::MacroInvocation> ( - new AST::MacroInvocation ( - AST::MacroInvocData (std::move (macro_path), - std::move (tok_tree)), - {}, locus)); + return AST::MacroInvocation::Regular ( + AST::MacroInvocData (std::move (macro_path), + std::move (tok_tree)), + {}, locus); } case PLUS: { // type param bounds @@ -9751,14 +9890,10 @@ Parser<ManagedTokenSource>::parse_bare_function_type ( std::move (return_type), best_try_locus)); } -// Parses a reference type (mutable or immutable, with given lifetime). template <typename ManagedTokenSource> std::unique_ptr<AST::ReferenceType> -Parser<ManagedTokenSource>::parse_reference_type () +Parser<ManagedTokenSource>::parse_reference_type_inner (Location locus) { - Location locus = lexer.peek_token ()->get_locus (); - skip_token (AMP); - // parse optional lifetime AST::Lifetime lifetime = AST::Lifetime::error (); if (lexer.peek_token ()->get_id () == LIFETIME) @@ -9797,6 +9932,29 @@ Parser<ManagedTokenSource>::parse_reference_type () std::move (lifetime))); } +// Parses a reference type (mutable or immutable, with given lifetime). +template <typename ManagedTokenSource> +std::unique_ptr<AST::ReferenceType> +Parser<ManagedTokenSource>::parse_reference_type () +{ + auto t = lexer.peek_token (); + auto locus = t->get_locus (); + + switch (t->get_id ()) + { + case AMP: + skip_token (AMP); + return parse_reference_type_inner (locus); + case LOGICAL_AND: + skip_token (LOGICAL_AND); + return std::unique_ptr<AST::ReferenceType> ( + new AST::ReferenceType (false, parse_reference_type_inner (locus), + locus)); + default: + gcc_unreachable (); + } +} + // Parses a raw (unsafe) pointer type. template <typename ManagedTokenSource> std::unique_ptr<AST::RawPointerType> @@ -9944,7 +10102,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () case ASTERISK: // raw pointer type return parse_raw_pointer_type (); - case AMP: // does this also include AMP_AMP? + case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND? + case LOGICAL_AND: // reference type return parse_reference_type (); case LIFETIME: @@ -10008,11 +10167,10 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () AST::DelimTokenTree tok_tree = parse_delim_token_tree (); - return std::unique_ptr<AST::MacroInvocation> ( - new AST::MacroInvocation ( - AST::MacroInvocData (std::move (macro_path), - std::move (tok_tree)), - {}, locus)); + return AST::MacroInvocation::Regular ( + AST::MacroInvocData (std::move (macro_path), + std::move (tok_tree)), + {}, locus); } default: // assume that this is a type path and not an error @@ -10767,6 +10925,15 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () return std::unique_ptr<AST::TuplePattern> ( new AST::TuplePattern (std::move (items), paren_locus)); } + else if (lexer.peek_token ()->get_id () == RIGHT_PAREN) + { + skip_token (RIGHT_PAREN); + auto items = std::unique_ptr<AST::TuplePatternItemsMultiple> ( + new AST::TuplePatternItemsMultiple ( + std::vector<std::unique_ptr<AST::Pattern>> ())); + return std::unique_ptr<AST::TuplePattern> ( + new AST::TuplePattern (std::move (items), paren_locus)); + } // parse initial pattern (required) std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); @@ -11694,8 +11861,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block () else if (t->get_str () == "macro_rules") { // macro_rules! macro item - std::unique_ptr<AST::MacroItem> item ( - parse_macro_item (std::move (outer_attrs))); + std::unique_ptr<AST::Item> item ( + parse_macro_rules_def (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION @@ -11872,18 +12039,17 @@ Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr ( { lexer.skip_token (); - std::unique_ptr<AST::MacroInvocation> stmt ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), - stmt_or_expr_loc, true)); + auto stmt + = AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), + stmt_or_expr_loc, true); return ExprOrStmt (std::move (stmt)); } // otherwise, create macro invocation - std::unique_ptr<AST::MacroInvocation> expr ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), - stmt_or_expr_loc, false)); + auto expr = AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), + stmt_or_expr_loc, false); return ExprOrStmt (std::move (expr)); } else @@ -12192,17 +12358,16 @@ Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi ( { lexer.skip_token (); - std::unique_ptr<AST::MacroInvocation> stmt ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), macro_locus, - true)); + auto stmt = AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), + macro_locus, true); return ExprOrStmt (std::move (stmt)); } // otherwise, create macro invocation - std::unique_ptr<AST::MacroInvocation> expr ( - new AST::MacroInvocation (std::move (invoc_data), - std::move (outer_attrs), macro_locus)); + auto expr + = AST::MacroInvocation::Regular (std::move (invoc_data), + std::move (outer_attrs), macro_locus); return ExprOrStmt (std::move (expr)); } else @@ -12883,6 +13048,12 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, case UNSAFE: return parse_unsafe_block_expr (std::move (outer_attrs), tok->get_locus ()); + case UNDERSCORE: + add_error ( + Error (tok->get_locus (), + "use of %qs is not allowed on the right-side of an assignment", + tok->get_token_description ())); + return nullptr; default: if (!restrictions.expr_can_be_null) add_error (Error (tok->get_locus (), @@ -14408,9 +14579,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_partial ( Location macro_locus = converted_path.get_locus (); - return std::unique_ptr<AST::MacroInvocation> (new AST::MacroInvocation ( + return AST::MacroInvocation::Regular ( AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)), - std::move (outer_attrs), macro_locus, restrictions.expr_can_be_stmt)); + std::move (outer_attrs), macro_locus, restrictions.expr_can_be_stmt); } /* Parses a struct expr struct with a path in expression already parsed (but diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 8449181..a4b65c5 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -150,6 +150,8 @@ public: std::unique_ptr<AST::TokenTree> parse_token_tree (); AST::Attribute parse_attribute_body (); AST::AttrVec parse_inner_attributes (); + std::unique_ptr<AST::MacroInvocation> + parse_macro_invocation (AST::AttrVec outer_attrs); private: void skip_after_semicolon (); @@ -197,10 +199,10 @@ private: AST::DelimTokenTree parse_delim_token_tree (); std::unique_ptr<AST::MacroRulesDefinition> parse_macro_rules_def (AST::AttrVec outer_attrs); + std::unique_ptr<AST::MacroRulesDefinition> + parse_decl_macro_def (AST::Visibility vis, AST::AttrVec outer_attrs); std::unique_ptr<AST::MacroInvocation> parse_macro_invocation_semi (AST::AttrVec outer_attrs); - std::unique_ptr<AST::MacroInvocation> - parse_macro_invocation (AST::AttrVec outer_attrs); AST::MacroRule parse_macro_rule (); AST::MacroMatcher parse_macro_matcher (); std::unique_ptr<AST::MacroMatch> parse_macro_match (); @@ -209,7 +211,6 @@ private: // Top-level item-related std::unique_ptr<AST::VisItem> parse_vis_item (AST::AttrVec outer_attrs); - std::unique_ptr<AST::MacroItem> parse_macro_item (AST::AttrVec outer_attrs); // VisItem subclass-related std::unique_ptr<AST::Module> parse_module (AST::Visibility vis, @@ -603,6 +604,8 @@ private: std::unique_ptr<AST::TypeNoBounds> parse_type_no_bounds (); std::unique_ptr<AST::TypeNoBounds> parse_slice_or_array_type (); std::unique_ptr<AST::RawPointerType> parse_raw_pointer_type (); + std::unique_ptr<AST::ReferenceType> + parse_reference_type_inner (Location locus); std::unique_ptr<AST::ReferenceType> parse_reference_type (); std::unique_ptr<AST::BareFunctionType> parse_bare_function_type (std::vector<AST::LifetimeParam> for_lifetimes); diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index 0a78d26..5b3f4a0 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -583,6 +583,10 @@ ResolverBase::visit (AST::SlicePattern &) {} void +ResolverBase::visit (AST::AltPattern &) +{} + +void ResolverBase::visit (AST::EmptyStmt &) {} diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 9d88f8f..aab1324 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -178,6 +178,7 @@ public: void visit (AST::TuplePattern &); void visit (AST::GroupedPattern &); void visit (AST::SlicePattern &); + void visit (AST::AltPattern &); void visit (AST::EmptyStmt &); void visit (AST::LetStmt &); diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 5f2b729..4c7d13a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -70,11 +70,9 @@ public: pattern.get_node_id (), pattern.get_locus (), type); } - void visit (AST::WildcardPattern &pattern) override + void visit (AST::GroupedPattern &pattern) override { - resolver->get_name_scope ().insert ( - CanonicalPath::new_seg (pattern.get_node_id (), "_"), - pattern.get_node_id (), pattern.get_locus (), type); + pattern.get_pattern_in_parens ()->accept_vis (*this); } // cases in a match expression diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 16d05f3..28ab069 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -589,6 +589,11 @@ ResolveGenericArgs::go (AST::GenericArgs &generic_args, resolver.resolve_disambiguated_generic (arg); } + + for (auto &binding : generic_args.get_binding_args ()) + { + ResolveType::go (binding.get_type ().get ()); + } } } // namespace Resolver diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc index 8100564..f5054f9 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.cc +++ b/gcc/rust/resolve/rust-early-name-resolver.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. @@ -24,20 +24,17 @@ namespace Rust { namespace Resolver { EarlyNameResolver::EarlyNameResolver () - : resolver (*Resolver::get ()), mappings (*Analysis::Mappings::get ()) + : current_scope (UNKNOWN_NODEID), resolver (*Resolver::get ()), + mappings (*Analysis::Mappings::get ()) {} void EarlyNameResolver::go (AST::Crate &crate) { - // FIXME: Is that valid? Why is the regular name resolution doing - // mappings->get_next_node_id()? - resolver.get_macro_scope ().push (crate.get_node_id ()); - - for (auto &item : crate.items) - item->accept_vis (*this); - - // FIXME: Should we pop the macro scope? + scoped (crate.get_node_id (), [&crate, this] () { + for (auto &item : crate.items) + item->accept_vis (*this); + }); } void @@ -335,11 +332,13 @@ EarlyNameResolver::visit (AST::ClosureExprInner &expr) void EarlyNameResolver::visit (AST::BlockExpr &expr) { - for (auto &stmt : expr.get_statements ()) - stmt->accept_vis (*this); + scoped (expr.get_node_id (), [&expr, this] () { + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); - if (expr.has_tail_expr ()) - expr.get_tail_expr ()->accept_vis (*this); + if (expr.has_tail_expr ()) + expr.get_tail_expr ()->accept_vis (*this); + }); } void @@ -434,8 +433,11 @@ EarlyNameResolver::visit (AST::WhileLetLoopExpr &expr) void EarlyNameResolver::visit (AST::ForLoopExpr &expr) { - expr.get_iterator_expr ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + scoped (expr.get_node_id (), [&expr, this] () { + expr.get_pattern ()->accept_vis (*this); + expr.get_iterator_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); + }); } void @@ -473,7 +475,9 @@ void EarlyNameResolver::visit (AST::IfLetExpr &expr) { expr.get_value_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); + + scoped (expr.get_node_id (), + [&expr, this] () { expr.get_if_block ()->accept_vis (*this); }); } void @@ -504,16 +508,21 @@ void EarlyNameResolver::visit (AST::MatchExpr &expr) { expr.get_scrutinee_expr ()->accept_vis (*this); - for (auto &match_arm : expr.get_match_cases ()) - { - if (match_arm.get_arm ().has_match_arm_guard ()) - match_arm.get_arm ().get_guard_expr ()->accept_vis (*this); - for (auto &pattern : match_arm.get_arm ().get_patterns ()) - pattern->accept_vis (*this); + scoped (expr.get_node_id (), [&expr, this] () { + for (auto &arm : expr.get_match_cases ()) + { + scoped (arm.get_node_id (), [&arm, this] () { + if (arm.get_arm ().has_match_arm_guard ()) + arm.get_arm ().get_guard_expr ()->accept_vis (*this); - match_arm.get_expr ()->accept_vis (*this); - } + for (auto &pattern : arm.get_arm ().get_patterns ()) + pattern->accept_vis (*this); + + arm.get_expr ()->accept_vis (*this); + }); + } + }); } void @@ -571,8 +580,10 @@ EarlyNameResolver::visit (AST::Method &method) void EarlyNameResolver::visit (AST::Module &module) { - for (auto &item : module.get_items ()) - item->accept_vis (*this); + scoped (module.get_node_id (), [&module, this] () { + for (auto &item : module.get_items ()) + item->accept_vis (*this); + }); } void @@ -722,8 +733,13 @@ EarlyNameResolver::visit (AST::TraitItemType &) void EarlyNameResolver::visit (AST::Trait &trait) { - for (auto &item : trait.get_trait_items ()) - item->accept_vis (*this); + for (auto &generic : trait.get_generic_params ()) + generic->accept_vis (*this); + + scoped (trait.get_node_id (), [&trait, this] () { + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); + }); } void @@ -734,8 +750,10 @@ EarlyNameResolver::visit (AST::InherentImpl &impl) for (auto &generic : impl.get_generic_params ()) generic->accept_vis (*this); - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); + scoped (impl.get_node_id (), [&impl, this] () { + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); + }); } void @@ -746,8 +764,10 @@ EarlyNameResolver::visit (AST::TraitImpl &impl) for (auto &generic : impl.get_generic_params ()) generic->accept_vis (*this); - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); + scoped (impl.get_node_id (), [&impl, this] () { + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); + }); } void @@ -772,8 +792,10 @@ EarlyNameResolver::visit (AST::ExternalFunctionItem &item) void EarlyNameResolver::visit (AST::ExternBlock &block) { - for (auto &item : block.get_extern_items ()) - item->accept_vis (*this); + scoped (block.get_node_id (), [&block, this] () { + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); + }); } void @@ -795,6 +817,15 @@ EarlyNameResolver::visit (AST::MacroRulesDefinition &rules_def) rules_def.get_rule_name ()); resolver.get_macro_scope ().insert (path, rules_def.get_node_id (), rules_def.get_locus ()); + + /* Since the EarlyNameResolver runs multiple time (fixed point algorithm) + * we could be inserting the same macro def over and over again until we + * implement some optimizations */ + // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead + AST::MacroRulesDefinition *tmp = nullptr; + if (mappings.lookup_macro_def (rules_def.get_node_id (), &tmp)) + return; + mappings.insert_macro_def (&rules_def); rust_debug_loc (rules_def.get_locus (), "inserting macro def: [%s]", path.get ().c_str ()); @@ -806,6 +837,10 @@ EarlyNameResolver::visit (AST::MacroInvocation &invoc) auto &invoc_data = invoc.get_invoc_data (); auto has_semicolon = invoc.has_semicolon (); + if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) + for (auto &pending_invoc : invoc.get_pending_eager_invocations ()) + pending_invoc->accept_vis (*this); + // ?? // switch on type of macro: // - '!' syntax macro (inner switch) @@ -847,6 +882,30 @@ EarlyNameResolver::visit (AST::MacroInvocation &invoc) bool ok = mappings.lookup_macro_def (resolved_node, &rules_def); rust_assert (ok); + auto &outer_attrs = rules_def->get_outer_attrs (); + bool is_builtin + = std::any_of (outer_attrs.begin (), outer_attrs.end (), + [] (AST::Attribute attr) { + return attr.get_path () == "rustc_builtin_macro"; + }); + + if (is_builtin) + { + auto builtin_kind + = AST::builtin_macro_from_string (rules_def->get_rule_name ()); + invoc.map_to_builtin (builtin_kind); + } + + auto attributes = rules_def->get_outer_attrs (); + + /* Since the EarlyNameResolver runs multiple time (fixed point algorithm) + * we could be inserting the same macro def over and over again until we + * implement some optimizations */ + // FIXME: ARTHUR: Remove that lookup and add proper optimizations instead + AST::MacroRulesDefinition *tmp_def = nullptr; + if (mappings.lookup_macro_invocation (invoc, &tmp_def)) + return; + mappings.insert_macro_invocation (invoc, rules_def); } @@ -994,6 +1053,13 @@ EarlyNameResolver::visit (AST::SlicePattern &pattern) } void +EarlyNameResolver::visit (AST::AltPattern &pattern) +{ + for (auto &alt : pattern.get_alts ()) + alt->accept_vis (*this); +} + +void EarlyNameResolver::visit (AST::EmptyStmt &) {} diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h index c53ab9f..84ee518 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.h +++ b/gcc/rust/resolve/rust-early-name-resolver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. @@ -35,6 +35,71 @@ public: void go (AST::Crate &crate); private: + /** + * Execute a lambda within a scope. This is equivalent to calling + * `enter_scope` before your code and `exit_scope` after. This ensures + * no errors can be committed + */ + void scoped (NodeId scope_id, std::function<void ()> fn) + { + auto old_scope = current_scope; + current_scope = scope_id; + resolver.get_macro_scope ().push (scope_id); + resolver.push_new_macro_rib (resolver.get_macro_scope ().peek ()); + + fn (); + + resolver.get_macro_scope ().pop (); + current_scope = old_scope; + } + + /** + * The "scope" we are currently in. + * + * This involves lexical scopes: + * + * ```rust + * // current_scope = crate_id; + * macro_rules! foo { () => {} ) + * + * { + * // current_scope = current_block_id; + * macro_rules! foo { () => { something!(); } } + * } + * // current_scope = crate_id; + * ``` + * + * as well as any sort of scope-like structure that might impact import name + * resolution or macro name resolution: + * + * ```rust + * macro_rules! foo { + * () => { fn empty() {} } + * } + * + * + * trait Foo { + * fn foo() { + * fn inner_foo() { + * macro_rules! foo { () => {} ) + * + * foo!(); + * } + * + * foo!(); + * } + * + * foo!(); + * } + * + * foo!(); + * ``` + */ + NodeId current_scope; + + /* The crate's scope */ + NodeId crate_scope; + Resolver &resolver; Analysis::Mappings &mappings; @@ -184,6 +249,7 @@ private: virtual void visit (AST::TuplePattern &pattern); virtual void visit (AST::GroupedPattern &pattern); virtual void visit (AST::SlicePattern &pattern); + virtual void visit (AST::AltPattern &pattern); virtual void visit (AST::EmptyStmt &stmt); virtual void visit (AST::LetStmt &stmt); virtual void visit (AST::ExprStmtWithoutBlock &stmt); diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 01c5fc4..076104f 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -26,7 +26,7 @@ #include "rust-location.h" #include "rust-linemap.h" #include "rust-diagnostics.h" -#include "operator.h" +#include "util/rust-operators.h" #include "tree.h" // Pointers to these types are created by the backend, passed to the diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc index c0f02c2..4e5c2ec 100644 --- a/gcc/rust/rust-diagnostics.cc +++ b/gcc/rust/rust-diagnostics.cc @@ -231,14 +231,49 @@ rust_debug_loc (const Location location, const char *fmt, ...) } namespace Rust { -Error::Error (const Location location, const char *fmt, ...) : locus (location) + +/** + * This function takes ownership of `args` and calls `va_end` on it + */ +static Error +va_constructor (Error::Kind kind, Location locus, const char *fmt, va_list args) + RUST_ATTRIBUTE_GCC_DIAG (3, 0); + +static Error +va_constructor (Error::Kind kind, Location locus, const char *fmt, va_list args) +{ + std::string message = expand_message (fmt, args); + message.shrink_to_fit (); + va_end (args); + + return Error (kind, locus, message); +} + +Error::Error (const Location location, const char *fmt, ...) + : kind (Kind::Err), locus (location) { va_list ap; + va_start (ap, fmt); + *this = va_constructor (Kind::Err, location, fmt, ap); +} + +Error +Error::Hint (const Location location, const char *fmt, ...) +{ + va_list ap; va_start (ap, fmt); - message = expand_message (fmt, ap); - va_end (ap); - message.shrink_to_fit (); + return va_constructor (Kind::Hint, location, fmt, ap); +} + +Error +Error::Fatal (const Location location, const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + + return va_constructor (Kind::FatalErr, location, fmt, ap); } + } // namespace Rust diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index 900198e..43fee8b 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -114,27 +114,69 @@ namespace Rust { * errors to be ignored, e.g. if backtracking. */ struct Error { + enum class Kind + { + Hint, + Err, + FatalErr, + }; + + Kind kind; Location locus; std::string message; // TODO: store more stuff? e.g. node id? - Error (Location locus, std::string message) - : locus (locus), message (std::move (message)) + Error (Kind kind, Location locus, std::string message) + : kind (kind), locus (locus), message (std::move (message)) { message.shrink_to_fit (); } + Error (Location locus, std::string message) + { + Error (Kind::Err, locus, std::move (message)); + } + + static Error Hint (Location locus, std::string message) + { + return Error (Kind::Hint, locus, std::move (message)); + } + + static Error Fatal (Location locus, std::string message) + { + return Error (Kind::FatalErr, locus, std::move (message)); + } + // TODO: the attribute part might be incorrect Error (Location locus, const char *fmt, ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4); - // Irreversibly emits the error as an error. - void emit_error () const { rust_error_at (locus, "%s", message.c_str ()); } + /** + * printf-like overload of Error::Hint + */ + static Error Hint (Location locus, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3); + + /** + * printf-like overload of Error::Fatal + */ + static Error Fatal (Location locus, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3); - // Irreversibly emits the error as a fatal error. - void emit_fatal_error () const + void emit () const { - rust_fatal_error (locus, "%s", message.c_str ()); + switch (kind) + { + case Kind::Hint: + rust_inform (locus, "%s", message.c_str ()); + break; + case Kind::Err: + rust_error_at (locus, "%s", message.c_str ()); + break; + case Kind::FatalErr: + rust_fatal_error (locus, "%s", message.c_str ()); + break; + } } }; } // namespace Rust diff --git a/gcc/rust/rust-gcc.h b/gcc/rust/rust-gcc.h index 085c16d..0db8194 100644 --- a/gcc/rust/rust-gcc.h +++ b/gcc/rust/rust-gcc.h @@ -1,5 +1,5 @@ // rust-gcc.cc -- Rust frontend to gcc IR. -// Copyright (C) 2011-2022 Free Software Foundation, Inc. +// Copyright (C) 2011-2023 Free Software Foundation, Inc. // Contributed by Ian Lance Taylor, Google. // forked from gccgo diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 732aabe..074bad9 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -27,6 +27,7 @@ #include "rust-hir-type-check.h" #include "rust-privacy-check.h" #include "rust-const-checker.h" +#include "rust-feature-gate.h" #include "rust-tycheck-dump.h" #include "rust-compile.h" #include "rust-cfg-parser.h" @@ -192,7 +193,7 @@ Session::handle_option ( else { rust_assert (!error.message.empty ()); - error.emit_error (); + error.emit (); } } else @@ -390,7 +391,7 @@ Session::handle_crate_name (const AST::Crate &parsed_crate) if (!validate_crate_name (msg_str, error)) { error.locus = attr.get_locus (); - error.emit_error (); + error.emit (); continue; } @@ -411,7 +412,7 @@ Session::handle_crate_name (const AST::Crate &parsed_crate) if (!options.crate_name_set_manually && !validate_crate_name (options.crate_name, error)) { - error.emit_error (); + error.emit (); rust_inform (linemap->get_location (0), "crate name inferred from this file"); } @@ -438,9 +439,9 @@ Session::compile_crate (const char *filename) "manner by passing the following flag:\n\n" "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by " "defining the following environment variable (any value will " - "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor" + "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor " "cargo-gccrs, this means passing\n\n" - "GCCRS_EXTRA_FLAGS=\"-frust-incomplete-and-experimental-compiler-do-not-" + "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-" "use\"\n\nas an environment variable."); RAIIFile file_wrap (filename); @@ -558,6 +559,9 @@ Session::compile_crate (const char *filename) rust_debug ("END POST-EXPANSION AST DUMP"); } + // feature gating + FeatureGate ().check (parsed_crate); + if (last_step == CompileOptions::CompileStep::NameResolution) return; @@ -817,9 +821,6 @@ Session::injection (AST::Crate &crate) void Session::expansion (AST::Crate &crate) { - /* We need to name resolve macros and imports here */ - Resolver::EarlyNameResolver ().go (crate); - rust_debug ("started expansion"); /* rustc has a modification to windows PATH temporarily here, which may end @@ -829,11 +830,41 @@ Session::expansion (AST::Crate &crate) // if not, would at least have to configure recursion_limit ExpansionCfg cfg; + auto fixed_point_reached = false; + unsigned iterations = 0; + // create extctxt? from parse session, cfg, and resolver? /* expand by calling cxtctxt object's monotonic_expander's expand_crate * method. */ MacroExpander expander (crate, cfg, *this); - expander.expand_crate (); + + while (!fixed_point_reached && iterations < cfg.recursion_limit) + { + /* We need to name resolve macros and imports here */ + Resolver::EarlyNameResolver ().go (crate); + + expander.expand_crate (); + + fixed_point_reached = !expander.has_changed (); + expander.reset_changed_state (); + iterations++; + + if (saw_errors ()) + break; + } + + if (iterations == cfg.recursion_limit) + { + auto last_invoc = expander.get_last_invocation (); + auto last_def = expander.get_last_definition (); + + rust_assert (last_def && last_invoc); + + RichLocation range (last_invoc->get_locus ()); + range.add_range (last_def->get_locus ()); + + rust_error_at (range, "reached recursion limit"); + } // error reporting - check unused macros, get missing fragment specifiers diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index fdf8eb9..bea4084 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -18,6 +18,7 @@ #include "rust-hir-type-check-base.h" #include "rust-coercion.h" +#include "rust-unify.h" namespace Rust { namespace Resolver { @@ -218,7 +219,10 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, // we might be able to replace this with a can_eq because we default // back to a final unity anyway rust_debug ("coerce_borrowed_pointer -- unify"); - TyTy::BaseType *result = receiver->unify (expected); + TyTy::BaseType *result + = UnifyRules::Resolve (TyTy::TyWithLocation (receiver), + TyTy::TyWithLocation (expected), locus, + true /* commit */, true /* emit_errors */); return CoercionResult{{}, result}; } } diff --git a/gcc/rust/typecheck/rust-hir-path-probe.cc b/gcc/rust/typecheck/rust-hir-path-probe.cc index cb3270d..dae4c01 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.cc +++ b/gcc/rust/typecheck/rust-hir-path-probe.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. @@ -18,10 +18,277 @@ #include "rust-hir-path-probe.h" #include "rust-hir-type-check-item.h" +#include "rust-hir-trait-resolve.h" namespace Rust { namespace Resolver { +// PathProbeCandidate + +PathProbeCandidate::Candidate::Candidate (EnumItemCandidate enum_field) + : enum_field (enum_field) +{} + +PathProbeCandidate::Candidate::Candidate (ImplItemCandidate impl) : impl (impl) +{} + +PathProbeCandidate::Candidate::Candidate (TraitItemCandidate trait) + : trait (trait) +{} + +PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, + Location locus, + EnumItemCandidate enum_field) + : type (type), ty (ty), locus (locus), item (enum_field) +{} + +PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, + Location locus, ImplItemCandidate impl) + : type (type), ty (ty), locus (locus), item (impl) +{} + +PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, + Location locus, + TraitItemCandidate trait) + : type (type), ty (ty), locus (locus), item (trait) +{} + +std::string +PathProbeCandidate::as_string () const +{ + return "PathProbe candidate TODO - as_string"; +} + +bool +PathProbeCandidate::is_enum_candidate () const +{ + return type == ENUM_VARIANT; +} + +bool +PathProbeCandidate::is_impl_candidate () const +{ + return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC; +} + +bool +PathProbeCandidate::is_trait_candidate () const +{ + return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS + || type == TRAIT_FUNC; +} + +bool +PathProbeCandidate::is_full_trait_item_candidate () const +{ + return is_trait_candidate () && item.trait.impl == nullptr; +} + +PathProbeCandidate +PathProbeCandidate::get_error () +{ + return PathProbeCandidate (ERROR, nullptr, Location (), + ImplItemCandidate{nullptr, nullptr}); +} + +bool +PathProbeCandidate::is_error () const +{ + return type == ERROR; +} + +DefId +PathProbeCandidate::get_defid () const +{ + switch (type) + { + case ENUM_VARIANT: + return item.enum_field.variant->get_defid (); + break; + + case IMPL_CONST: + case IMPL_TYPE_ALIAS: + case IMPL_FUNC: + return item.impl.impl_item->get_impl_mappings ().get_defid (); + break; + + case TRAIT_ITEM_CONST: + case TRAIT_TYPE_ALIAS: + case TRAIT_FUNC: + return item.trait.item_ref->get_mappings ().get_defid (); + break; + + case ERROR: + default: + return UNKNOWN_DEFID; + } + + return UNKNOWN_DEFID; +} + +bool +PathProbeCandidate::operator< (const PathProbeCandidate &c) const +{ + return get_defid () < c.get_defid (); +} + +// PathProbeType + +PathProbeType::PathProbeType (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &query, + DefId specific_trait_id) + : TypeCheckBase (), receiver (receiver), search (query), + current_impl (nullptr), specific_trait_id (specific_trait_id) +{} + +std::set<PathProbeCandidate> +PathProbeType::Probe (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &segment_name, + bool probe_impls, bool probe_bounds, + bool ignore_mandatory_trait_items, + DefId specific_trait_id) +{ + PathProbeType probe (receiver, segment_name, specific_trait_id); + if (probe_impls) + { + if (receiver->get_kind () == TyTy::TypeKind::ADT) + { + const TyTy::ADTType *adt + = static_cast<const TyTy::ADTType *> (receiver); + if (adt->is_enum ()) + probe.process_enum_item_for_candiates (adt); + } + + probe.process_impl_items_for_candidates (); + } + + if (!probe_bounds) + return probe.candidates; + + if (!probe.is_reciever_generic ()) + { + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds + = TypeBoundsProbe::Probe (receiver); + for (auto &candidate : probed_bounds) + { + const TraitReference *trait_ref = candidate.first; + if (specific_trait_id != UNKNOWN_DEFID) + { + if (trait_ref->get_mappings ().get_defid () != specific_trait_id) + continue; + } + + HIR::ImplBlock *impl = candidate.second; + probe.process_associated_trait_for_candidates ( + trait_ref, impl, ignore_mandatory_trait_items); + } + } + + for (const TyTy::TypeBoundPredicate &predicate : + receiver->get_specified_bounds ()) + { + const TraitReference *trait_ref = predicate.get (); + if (specific_trait_id != UNKNOWN_DEFID) + { + if (trait_ref->get_mappings ().get_defid () != specific_trait_id) + continue; + } + + probe.process_predicate_for_candidates (predicate, + ignore_mandatory_trait_items); + } + + return probe.candidates; +} + +void +PathProbeType::visit (HIR::TypeAlias &alias) +{ + Identifier name = alias.get_new_type_name (); + if (search.as_string ().compare (name) == 0) + { + HirId tyid = alias.get_mappings ().get_hirid (); + TyTy::BaseType *ty = nullptr; + bool ok = query_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias, + current_impl}; + PathProbeCandidate candidate{ + PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty, + alias.get_locus (), impl_item_candidate}; + candidates.insert (std::move (candidate)); + } +} + +void +PathProbeType::visit (HIR::ConstantItem &constant) +{ + 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 = query_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant, + current_impl}; + PathProbeCandidate candidate{ + PathProbeCandidate::CandidateType::IMPL_CONST, ty, + constant.get_locus (), impl_item_candidate}; + candidates.insert (std::move (candidate)); + } +} + +void +PathProbeType::visit (HIR::Function &function) +{ + 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 = query_type (tyid, &ty); + rust_assert (ok); + + PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function, + current_impl}; + PathProbeCandidate candidate{PathProbeCandidate::CandidateType::IMPL_FUNC, + ty, function.get_locus (), + impl_item_candidate}; + candidates.insert (std::move (candidate)); + } +} + +void +PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType *adt) +{ + if (specific_trait_id != UNKNOWN_DEFID) + return; + + TyTy::VariantDef *v; + if (!adt->lookup_variant (search.as_string (), &v)) + return; + + PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v}; + PathProbeCandidate candidate{PathProbeCandidate::CandidateType::ENUM_VARIANT, + receiver->clone (), + mappings->lookup_location (adt->get_ty_ref ()), + enum_item_candidate}; + candidates.insert (std::move (candidate)); +} + +void +PathProbeType::process_impl_items_for_candidates () +{ + mappings->iterate_impl_items ( + [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { + process_impl_item_candidate (id, item, impl); + return true; + }); +} + void PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) @@ -42,5 +309,191 @@ PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item, item->accept_vis (*this); } +void +PathProbeType::process_associated_trait_for_candidates ( + const TraitReference *trait_ref, HIR::ImplBlock *impl, + bool ignore_mandatory_trait_items) +{ + const TraitItemReference *trait_item_ref = nullptr; + if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref)) + return; + + bool trait_item_needs_implementation = !trait_item_ref->is_optional (); + if (ignore_mandatory_trait_items && trait_item_needs_implementation) + return; + + PathProbeCandidate::CandidateType candidate_type; + switch (trait_item_ref->get_trait_item_type ()) + { + case TraitItemReference::TraitItemType::FN: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; + break; + case TraitItemReference::TraitItemType::CONST: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST; + break; + case TraitItemReference::TraitItemType::TYPE: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS; + break; + + case TraitItemReference::TraitItemType::ERROR: + default: + gcc_unreachable (); + break; + } + + TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty (); + + // we can substitute the Self with the receiver here + if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) + { + TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty); + TyTy::SubstitutionParamMapping *param = nullptr; + for (auto ¶m_mapping : fn->get_substs ()) + { + const HIR::TypeParam &type_param = param_mapping.get_generic_param (); + if (type_param.get_type_representation ().compare ("Self") == 0) + { + param = ¶m_mapping; + break; + } + } + rust_assert (param != nullptr); + + std::vector<TyTy::SubstitutionArg> mappings; + mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ())); + + Location locus; // FIXME + TyTy::SubstitutionArgumentMappings args (std::move (mappings), {}, locus); + trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args); + } + + PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref, + trait_item_ref, + impl}; + + PathProbeCandidate candidate{candidate_type, trait_item_tyty, + trait_item_ref->get_locus (), + trait_item_candidate}; + candidates.insert (std::move (candidate)); +} + +void +PathProbeType::process_predicate_for_candidates ( + const TyTy::TypeBoundPredicate &predicate, bool ignore_mandatory_trait_items) +{ + const TraitReference *trait_ref = predicate.get (); + + TyTy::TypeBoundPredicateItem item + = predicate.lookup_associated_item (search.as_string ()); + if (item.is_error ()) + return; + + if (ignore_mandatory_trait_items && item.needs_implementation ()) + return; + + const TraitItemReference *trait_item_ref = item.get_raw_item (); + PathProbeCandidate::CandidateType candidate_type; + switch (trait_item_ref->get_trait_item_type ()) + { + case TraitItemReference::TraitItemType::FN: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; + break; + case TraitItemReference::TraitItemType::CONST: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST; + break; + case TraitItemReference::TraitItemType::TYPE: + candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS; + break; + + case TraitItemReference::TraitItemType::ERROR: + default: + gcc_unreachable (); + break; + } + + TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver); + PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref, + trait_item_ref, + nullptr}; + PathProbeCandidate candidate{candidate_type, trait_item_tyty, + trait_item_ref->get_locus (), + trait_item_candidate}; + candidates.insert (std::move (candidate)); +} + +std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> +PathProbeType::union_bounds ( + const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>> a, + const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b) + const +{ + std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper; + for (auto &ref : a) + { + mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); + } + for (auto &ref : b) + { + mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); + } + + std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set; + for (auto it = mapper.begin (); it != mapper.end (); it++) + { + union_set.push_back ({it->second.first, it->second.second}); + } + return union_set; +} + +bool +PathProbeType::is_reciever_generic () const +{ + const TyTy::BaseType *root = receiver->get_root (); + bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC; + return receiver_is_type_param || receiver_is_dyn; +} + +// PathProbImplTrait + +PathProbeImplTrait::PathProbeImplTrait (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &query, + const TraitReference *trait_reference) + : PathProbeType (receiver, query, UNKNOWN_DEFID), + trait_reference (trait_reference) +{} + +std::set<PathProbeCandidate> +PathProbeImplTrait::Probe (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &segment_name, + const TraitReference *trait_reference) +{ + PathProbeImplTrait probe (receiver, segment_name, trait_reference); + // iterate all impls for this trait and receiver + // then search for possible candidates using base class behaviours + probe.process_trait_impl_items_for_candidates (); + return probe.candidates; +} + +void +PathProbeImplTrait::process_trait_impl_items_for_candidates () +{ + mappings->iterate_impl_items ( + [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { + // just need to check if this is an impl block for this trait the next + // function checks the receiver + if (!impl->has_trait_ref ()) + return true; + + TraitReference *resolved + = TraitResolver::Lookup (*(impl->get_trait_ref ().get ())); + if (!trait_reference->is_equal (*resolved)) + return true; + + process_impl_item_candidate (id, item, impl); + return true; + }); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 6d6bcf8..dd511ac 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -73,89 +73,37 @@ struct PathProbeCandidate ImplItemCandidate impl; TraitItemCandidate trait; - Candidate (EnumItemCandidate enum_field) : enum_field (enum_field) {} - Candidate (ImplItemCandidate impl) : impl (impl) {} - Candidate (TraitItemCandidate trait) : trait (trait) {} + Candidate (EnumItemCandidate enum_field); + Candidate (ImplItemCandidate impl); + Candidate (TraitItemCandidate trait); } item; PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus, - EnumItemCandidate enum_field) - : type (type), ty (ty), locus (locus), item (enum_field) - {} + EnumItemCandidate enum_field); PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus, - ImplItemCandidate impl) - : type (type), ty (ty), locus (locus), item (impl) - {} + ImplItemCandidate impl); PathProbeCandidate (CandidateType type, TyTy::BaseType *ty, Location locus, - TraitItemCandidate trait) - : type (type), ty (ty), locus (locus), item (trait) - {} + TraitItemCandidate trait); - std::string as_string () const - { - return "PathProbe candidate TODO - as_string"; - } + std::string as_string () const; - bool is_enum_candidate () const { return type == ENUM_VARIANT; } + bool is_enum_candidate () const; - bool is_impl_candidate () const - { - return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC; - } + bool is_impl_candidate () const; - bool is_trait_candidate () const - { - return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS - || type == TRAIT_FUNC; - } + bool is_trait_candidate () const; - bool is_full_trait_item_candidate () const - { - return is_trait_candidate () && item.trait.impl == nullptr; - } + bool is_full_trait_item_candidate () const; - static PathProbeCandidate get_error () - { - return PathProbeCandidate (ERROR, nullptr, Location (), - ImplItemCandidate{nullptr, nullptr}); - } + static PathProbeCandidate get_error (); - bool is_error () const { return type == ERROR; } + bool is_error () const; - DefId get_defid () const - { - switch (type) - { - case ENUM_VARIANT: - return item.enum_field.variant->get_defid (); - break; - - case IMPL_CONST: - case IMPL_TYPE_ALIAS: - case IMPL_FUNC: - return item.impl.impl_item->get_impl_mappings ().get_defid (); - break; - - case TRAIT_ITEM_CONST: - case TRAIT_TYPE_ALIAS: - case TRAIT_FUNC: - return item.trait.item_ref->get_mappings ().get_defid (); - break; - - case ERROR: - default: - return UNKNOWN_DEFID; - } - - return UNKNOWN_DEFID; - } + DefId get_defid () const; - bool operator< (const PathProbeCandidate &c) const - { - return get_defid () < c.get_defid (); - } + bool operator< (const PathProbeCandidate &c) const; }; class PathProbeType : public TypeCheckBase, public HIR::HIRImplVisitor @@ -165,144 +113,16 @@ public: Probe (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, bool probe_impls, bool probe_bounds, bool ignore_mandatory_trait_items, - DefId specific_trait_id = UNKNOWN_DEFID) - { - PathProbeType probe (receiver, segment_name, specific_trait_id); - if (probe_impls) - { - if (receiver->get_kind () == TyTy::TypeKind::ADT) - { - const TyTy::ADTType *adt - = static_cast<const TyTy::ADTType *> (receiver); - if (adt->is_enum ()) - probe.process_enum_item_for_candiates (adt); - } - - probe.process_impl_items_for_candidates (); - } - - if (!probe_bounds) - return probe.candidates; - - if (!probe.is_reciever_generic ()) - { - std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds - = TypeBoundsProbe::Probe (receiver); - for (auto &candidate : probed_bounds) - { - const TraitReference *trait_ref = candidate.first; - if (specific_trait_id != UNKNOWN_DEFID) - { - if (trait_ref->get_mappings ().get_defid () - != specific_trait_id) - continue; - } - - HIR::ImplBlock *impl = candidate.second; - probe.process_associated_trait_for_candidates ( - trait_ref, impl, ignore_mandatory_trait_items); - } - } - - for (const TyTy::TypeBoundPredicate &predicate : - receiver->get_specified_bounds ()) - { - const TraitReference *trait_ref = predicate.get (); - if (specific_trait_id != UNKNOWN_DEFID) - { - if (trait_ref->get_mappings ().get_defid () != specific_trait_id) - continue; - } - - probe.process_predicate_for_candidates (predicate, - ignore_mandatory_trait_items); - } - - return probe.candidates; - } - - void visit (HIR::TypeAlias &alias) override - { - Identifier name = alias.get_new_type_name (); - if (search.as_string ().compare (name) == 0) - { - HirId tyid = alias.get_mappings ().get_hirid (); - TyTy::BaseType *ty = nullptr; - bool ok = query_type (tyid, &ty); - rust_assert (ok); - - PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias, - current_impl}; - PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty, - alias.get_locus (), impl_item_candidate}; - candidates.insert (std::move (candidate)); - } - } - - 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 = query_type (tyid, &ty); - rust_assert (ok); - - PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant, - current_impl}; - PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_CONST, ty, - constant.get_locus (), impl_item_candidate}; - candidates.insert (std::move (candidate)); - } - } + DefId specific_trait_id = UNKNOWN_DEFID); - 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 = query_type (tyid, &ty); - rust_assert (ok); - - PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function, - current_impl}; - PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::IMPL_FUNC, ty, - function.get_locus (), impl_item_candidate}; - candidates.insert (std::move (candidate)); - } - } + void visit (HIR::TypeAlias &alias) override; + void visit (HIR::ConstantItem &constant) override; + void visit (HIR::Function &function) override; protected: - void process_enum_item_for_candiates (const TyTy::ADTType *adt) - { - if (specific_trait_id != UNKNOWN_DEFID) - return; - - TyTy::VariantDef *v; - if (!adt->lookup_variant (search.as_string (), &v)) - return; - - PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v}; - PathProbeCandidate candidate{ - PathProbeCandidate::CandidateType::ENUM_VARIANT, receiver->clone (), - mappings->lookup_location (adt->get_ty_ref ()), enum_item_candidate}; - candidates.insert (std::move (candidate)); - } + void process_enum_item_for_candiates (const TyTy::ADTType *adt); - void process_impl_items_for_candidates () - { - mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item, - HIR::ImplBlock *impl) mutable -> bool { - process_impl_item_candidate (id, item, impl); - return true; - }); - } + void process_impl_items_for_candidates (); void process_impl_item_candidate (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl); @@ -310,155 +130,24 @@ protected: void process_associated_trait_for_candidates (const TraitReference *trait_ref, HIR::ImplBlock *impl, - bool ignore_mandatory_trait_items) - { - const TraitItemReference *trait_item_ref = nullptr; - if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref)) - return; - - bool trait_item_needs_implementation = !trait_item_ref->is_optional (); - if (ignore_mandatory_trait_items && trait_item_needs_implementation) - return; - - PathProbeCandidate::CandidateType candidate_type; - switch (trait_item_ref->get_trait_item_type ()) - { - case TraitItemReference::TraitItemType::FN: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; - break; - case TraitItemReference::TraitItemType::CONST: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST; - break; - case TraitItemReference::TraitItemType::TYPE: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS; - break; - - case TraitItemReference::TraitItemType::ERROR: - default: - gcc_unreachable (); - break; - } - - TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty (); - - // we can substitute the Self with the receiver here - if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF) - { - TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty); - TyTy::SubstitutionParamMapping *param = nullptr; - for (auto ¶m_mapping : fn->get_substs ()) - { - const HIR::TypeParam &type_param - = param_mapping.get_generic_param (); - if (type_param.get_type_representation ().compare ("Self") == 0) - { - param = ¶m_mapping; - break; - } - } - rust_assert (param != nullptr); - - std::vector<TyTy::SubstitutionArg> mappings; - mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ())); - - Location locus; // FIXME - TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus); - trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args); - } - - PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref, - trait_item_ref, - impl}; - - PathProbeCandidate candidate{candidate_type, trait_item_tyty, - trait_item_ref->get_locus (), - trait_item_candidate}; - candidates.insert (std::move (candidate)); - } + bool ignore_mandatory_trait_items); void process_predicate_for_candidates (const TyTy::TypeBoundPredicate &predicate, - bool ignore_mandatory_trait_items) - { - const TraitReference *trait_ref = predicate.get (); - - TyTy::TypeBoundPredicateItem item - = predicate.lookup_associated_item (search.as_string ()); - if (item.is_error ()) - return; - - if (ignore_mandatory_trait_items && item.needs_implementation ()) - return; - - const TraitItemReference *trait_item_ref = item.get_raw_item (); - PathProbeCandidate::CandidateType candidate_type; - switch (trait_item_ref->get_trait_item_type ()) - { - case TraitItemReference::TraitItemType::FN: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC; - break; - case TraitItemReference::TraitItemType::CONST: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST; - break; - case TraitItemReference::TraitItemType::TYPE: - candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS; - break; - - case TraitItemReference::TraitItemType::ERROR: - default: - gcc_unreachable (); - break; - } - - TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver); - PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref, - trait_item_ref, - nullptr}; - PathProbeCandidate candidate{candidate_type, trait_item_tyty, - trait_item_ref->get_locus (), - trait_item_candidate}; - candidates.insert (std::move (candidate)); - } + bool ignore_mandatory_trait_items); protected: PathProbeType (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &query, DefId specific_trait_id) - : TypeCheckBase (), receiver (receiver), search (query), - current_impl (nullptr), specific_trait_id (specific_trait_id) - {} + const HIR::PathIdentSegment &query, DefId specific_trait_id); std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_bounds ( const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>> a, const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b) - const - { - std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper; - for (auto &ref : a) - { - mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); - } - for (auto &ref : b) - { - mapper.insert ({ref.first->get_mappings ().get_defid (), ref}); - } - - std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set; - for (auto it = mapper.begin (); it != mapper.end (); it++) - { - union_set.push_back ({it->second.first, it->second.second}); - } - return union_set; - } + const; - bool is_reciever_generic () const - { - const TyTy::BaseType *root = receiver->get_root (); - bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; - bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC; - return receiver_is_type_param || receiver_is_dyn; - } + bool is_reciever_generic () const; const TyTy::BaseType *receiver; const HIR::PathIdentSegment &search; @@ -488,24 +177,14 @@ public: static std::set<PathProbeCandidate> Probe (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, - const TraitReference *trait_reference) - { - PathProbeImplTrait probe (receiver, segment_name, trait_reference); - // iterate all impls for this trait and receiver - // then search for possible candidates using base class behaviours - probe.process_trait_impl_items_for_candidates (); - return probe.candidates; - } + const TraitReference *trait_reference); private: - void process_trait_impl_items_for_candidates (); - PathProbeImplTrait (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, - const TraitReference *trait_reference) - : PathProbeType (receiver, query, UNKNOWN_DEFID), - trait_reference (trait_reference) - {} + const TraitReference *trait_reference); + + void process_trait_impl_items_for_candidates (); const TraitReference *trait_reference; }; diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h deleted file mode 100644 index 0df3526..0000000 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright (C) 2021-2023 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_TRAIT_REF_H -#define RUST_HIR_TRAIT_REF_H - -#include "rust-hir-full.h" -#include "rust-tyty-visitor.h" -#include "rust-hir-type-check-util.h" - -namespace Rust { -namespace Resolver { - -// Data Objects for the associated trait items in a structure we can work with -// https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html -class TypeCheckContext; -class TraitItemReference -{ -public: - enum TraitItemType - { - FN, - CONST, - TYPE, - ERROR - }; - - TraitItemReference (std::string identifier, bool optional, TraitItemType type, - HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, - std::vector<TyTy::SubstitutionParamMapping> substitutions, - Location locus); - - TraitItemReference (TraitItemReference const &other); - - TraitItemReference &operator= (TraitItemReference const &other); - - static TraitItemReference error () - { - return TraitItemReference ("", false, ERROR, nullptr, nullptr, {}, - Location ()); - } - - static TraitItemReference &error_node () - { - static TraitItemReference error = TraitItemReference::error (); - return error; - } - - bool is_error () const { return type == ERROR; } - - std::string as_string () const - { - return "(" + trait_item_type_as_string (type) + " " + identifier + " " - + ")"; - } - - static std::string trait_item_type_as_string (TraitItemType ty) - { - switch (ty) - { - case FN: - return "FN"; - case CONST: - return "CONST"; - case TYPE: - return "TYPE"; - case ERROR: - return "ERROR"; - } - return "ERROR"; - } - - bool is_optional () const { return optional_flag; } - - std::string get_identifier () const { return identifier; } - - TraitItemType get_trait_item_type () const { return type; } - - HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; } - - Location get_locus () const { return locus; } - - const Analysis::NodeMapping get_mappings () const - { - return hir_trait_item->get_mappings (); - } - - TyTy::BaseType *get_tyty () const - { - rust_assert (hir_trait_item != nullptr); - - switch (type) - { - case CONST: - return get_type_from_constant ( - static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item)); - break; - - case TYPE: - return get_type_from_typealias ( - static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item)); - - case FN: - return get_type_from_fn ( - static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item)); - break; - - default: - return get_error (); - } - - gcc_unreachable (); - return get_error (); - } - - Analysis::NodeMapping get_parent_trait_mappings () const; - - // this is called when the trait is completed resolution and gives the items a - // chance to run their specific type resolution passes. If we call their - // resolution on construction it can lead to a case where the trait being - // resolved recursively trying to resolve the trait itself infinitely since - // the trait will not be stored in its own map yet - void on_resolved (); - - void associated_type_set (TyTy::BaseType *ty) const; - - void associated_type_reset () const; - - bool is_object_safe () const; - -private: - TyTy::ErrorType *get_error () const - { - return new TyTy::ErrorType (get_mappings ().get_hirid ()); - } - - TyTy::BaseType *get_type_from_typealias (/*const*/ - HIR::TraitItemType &type) const; - - TyTy::BaseType * - get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const; - - TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const; - - bool is_item_resolved () const; - void resolve_item (HIR::TraitItemType &type); - void resolve_item (HIR::TraitItemConst &constant); - void resolve_item (HIR::TraitItemFunc &func); - - std::string identifier; - bool optional_flag; - TraitItemType type; - HIR::TraitItem *hir_trait_item; - std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions; - Location locus; - - TyTy::BaseType - *self; // this is the implict Self TypeParam required for methods - Resolver::TypeCheckContext *context; -}; - -// this wraps up the HIR::Trait so we can do analysis on it - -class TraitReference -{ -public: - TraitReference (const HIR::Trait *hir_trait_ref, - std::vector<TraitItemReference> item_refs, - std::vector<const TraitReference *> super_traits, - std::vector<TyTy::SubstitutionParamMapping> substs) - : hir_trait_ref (hir_trait_ref), item_refs (item_refs), - super_traits (super_traits) - { - trait_substs.clear (); - trait_substs.reserve (substs.size ()); - for (const auto &p : substs) - trait_substs.push_back (p.clone ()); - } - - TraitReference (TraitReference const &other) - : hir_trait_ref (other.hir_trait_ref), item_refs (other.item_refs), - super_traits (other.super_traits) - { - trait_substs.clear (); - trait_substs.reserve (other.trait_substs.size ()); - for (const auto &p : other.trait_substs) - trait_substs.push_back (p.clone ()); - } - - TraitReference &operator= (TraitReference const &other) - { - hir_trait_ref = other.hir_trait_ref; - item_refs = other.item_refs; - super_traits = other.super_traits; - - trait_substs.clear (); - trait_substs.reserve (other.trait_substs.size ()); - for (const auto &p : other.trait_substs) - trait_substs.push_back (p.clone ()); - - return *this; - } - - TraitReference (TraitReference &&other) = default; - TraitReference &operator= (TraitReference &&other) = default; - - static TraitReference error () - { - return TraitReference (nullptr, {}, {}, {}); - } - - bool is_error () const { return hir_trait_ref == nullptr; } - - static TraitReference &error_node () - { - static TraitReference trait_error_node = TraitReference::error (); - return trait_error_node; - } - - Location get_locus () const { return hir_trait_ref->get_locus (); } - - std::string get_name () const - { - rust_assert (!is_error ()); - return hir_trait_ref->get_name (); - } - - std::string as_string () const - { - if (is_error ()) - return "<trait-ref-error-node>"; - - std::string item_buf; - for (auto &item : item_refs) - { - item_buf += item.as_string () + ", "; - } - return "HIR Trait: " + get_name () + "->" - + hir_trait_ref->get_mappings ().as_string () + " [" + item_buf - + "]"; - } - - const HIR::Trait *get_hir_trait_ref () const { return hir_trait_ref; } - - const Analysis::NodeMapping &get_mappings () const - { - return hir_trait_ref->get_mappings (); - } - - DefId get_defid () const { return get_mappings ().get_defid (); } - - bool lookup_hir_trait_item (const HIR::TraitItem &item, - TraitItemReference **ref) - { - return lookup_trait_item (item.trait_identifier (), ref); - } - - bool lookup_trait_item (const std::string &ident, TraitItemReference **ref) - { - for (auto &item : item_refs) - { - if (ident.compare (item.get_identifier ()) == 0) - { - *ref = &item; - return true; - } - } - return false; - } - - bool lookup_trait_item_by_type (const std::string &ident, - TraitItemReference::TraitItemType type, - TraitItemReference **ref) - { - for (auto &item : item_refs) - { - if (item.get_trait_item_type () != type) - continue; - - if (ident.compare (item.get_identifier ()) == 0) - { - *ref = &item; - return true; - } - } - return false; - } - - bool lookup_trait_item_by_type (const std::string &ident, - TraitItemReference::TraitItemType type, - const TraitItemReference **ref) const - { - for (auto &item : item_refs) - { - if (item.get_trait_item_type () != type) - continue; - - if (ident.compare (item.get_identifier ()) == 0) - { - *ref = &item; - return true; - } - } - return false; - } - - bool lookup_hir_trait_item (const HIR::TraitItem &item, - const TraitItemReference **ref) const - { - return lookup_trait_item (item.trait_identifier (), ref); - } - - bool lookup_trait_item (const std::string &ident, - const TraitItemReference **ref) const - { - for (auto &item : item_refs) - { - if (ident.compare (item.get_identifier ()) == 0) - { - *ref = &item; - return true; - } - } - - // lookup super traits - for (const auto &super_trait : super_traits) - { - bool found = super_trait->lookup_trait_item (ident, ref); - if (found) - return true; - } - - return false; - } - - const TraitItemReference * - lookup_trait_item (const std::string &ident, - TraitItemReference::TraitItemType type) const - { - for (auto &item : item_refs) - { - if (item.get_trait_item_type () != type) - continue; - - if (ident.compare (item.get_identifier ()) == 0) - return &item; - } - - // lookup super traits - for (const auto &super_trait : super_traits) - { - const TraitItemReference *res - = super_trait->lookup_trait_item (ident, type); - if (!res->is_error ()) - return res; - } - - return &TraitItemReference::error_node (); - } - - size_t size () const { return item_refs.size (); } - - const std::vector<TraitItemReference> &get_trait_items () const - { - return item_refs; - } - - void get_trait_items_and_supers ( - std::vector<const TraitItemReference *> &result) const - { - for (const auto &item : item_refs) - result.push_back (&item); - - for (const auto &super_trait : super_traits) - super_trait->get_trait_items_and_supers (result); - } - - void on_resolved () - { - for (auto &item : item_refs) - { - item.on_resolved (); - } - } - - void clear_associated_types () - { - for (auto &item : item_refs) - { - bool is_assoc_type = item.get_trait_item_type () - == TraitItemReference::TraitItemType::TYPE; - if (is_assoc_type) - item.associated_type_reset (); - } - } - - bool is_equal (const TraitReference &other) const - { - DefId this_id = get_mappings ().get_defid (); - DefId other_id = other.get_mappings ().get_defid (); - return this_id == other_id; - } - - const std::vector<const TraitReference *> get_super_traits () const - { - return super_traits; - } - - bool is_object_safe (bool emit_error, Location locus) const - { - // https: // doc.rust-lang.org/reference/items/traits.html#object-safety - std::vector<const TraitReference *> non_object_super_traits; - for (auto &item : super_traits) - { - if (!item->is_object_safe (false, Location ())) - non_object_super_traits.push_back (item); - } - - std::vector<const Resolver::TraitItemReference *> non_object_safe_items; - for (auto &item : get_trait_items ()) - { - if (!item.is_object_safe ()) - non_object_safe_items.push_back (&item); - } - - bool is_safe - = non_object_super_traits.empty () && non_object_safe_items.empty (); - if (emit_error && !is_safe) - { - RichLocation r (locus); - for (auto &item : non_object_super_traits) - r.add_range (item->get_locus ()); - for (auto &item : non_object_safe_items) - r.add_range (item->get_locus ()); - - rust_error_at (r, "trait bound is not object safe"); - } - - return is_safe; - } - - bool trait_has_generics () const { return !trait_substs.empty (); } - - std::vector<TyTy::SubstitutionParamMapping> get_trait_substs () const - { - return trait_substs; - } - - bool satisfies_bound (const TraitReference &reference) const - { - if (is_equal (reference)) - return true; - - for (const auto &super_trait : super_traits) - { - if (super_trait->satisfies_bound (reference)) - return true; - } - - return false; - } - -private: - const HIR::Trait *hir_trait_ref; - std::vector<TraitItemReference> item_refs; - std::vector<const TraitReference *> super_traits; - std::vector<TyTy::SubstitutionParamMapping> trait_substs; -}; - -class AssociatedImplTrait -{ -public: - AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl, - TyTy::BaseType *self, - Resolver::TypeCheckContext *context) - : trait (trait), impl (impl), self (self), context (context) - {} - - TraitReference *get_trait () { return trait; } - - HIR::ImplBlock *get_impl_block () { return impl; } - - TyTy::BaseType *get_self () { return self; } - - void setup_associated_types (const TyTy::BaseType *self, - const TyTy::TypeBoundPredicate &bound); - - void reset_associated_types (); - -private: - TraitReference *trait; - HIR::ImplBlock *impl; - TyTy::BaseType *self; - Resolver::TypeCheckContext *context; -}; - -} // namespace Resolver -} // namespace Rust - -#endif // RUST_HIR_TRAIT_REF_H diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc new file mode 100644 index 0000000..a1229ad --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -0,0 +1,475 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-hir-trait-reference.h" + +namespace Rust { +namespace Resolver { + +std::string +TraitItemReference::as_string () const +{ + return "(" + trait_item_type_as_string (type) + " " + identifier + " " + ")"; +} + +bool +TraitItemReference::is_error () const +{ + return type == ERROR; +} + +bool +TraitItemReference::is_optional () const +{ + return optional_flag; +}; + +std::string +TraitItemReference::get_identifier () const +{ + return identifier; +} + +TraitItemReference::TraitItemType +TraitItemReference::get_trait_item_type () const +{ + return type; +} + +HIR::TraitItem * +TraitItemReference::get_hir_trait_item () const +{ + return hir_trait_item; +} + +Location +TraitItemReference::get_locus () const +{ + return locus; +} + +const Analysis::NodeMapping +TraitItemReference::get_mappings () const +{ + return hir_trait_item->get_mappings (); +} + +TyTy::BaseType * +TraitItemReference::get_tyty () const +{ + rust_assert (hir_trait_item != nullptr); + + switch (type) + { + case CONST: + return get_type_from_constant ( + static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item)); + break; + + case TYPE: + return get_type_from_typealias ( + static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item)); + + case FN: + return get_type_from_fn ( + static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item)); + break; + + default: + return get_error (); + } + + gcc_unreachable (); + return get_error (); +} + +TyTy::ErrorType * +TraitItemReference::get_error () const +{ + return new TyTy::ErrorType (get_mappings ().get_hirid ()); +} + +TraitReference::TraitReference ( + const HIR::Trait *hir_trait_ref, std::vector<TraitItemReference> item_refs, + std::vector<const TraitReference *> super_traits, + std::vector<TyTy::SubstitutionParamMapping> substs) + : hir_trait_ref (hir_trait_ref), item_refs (item_refs), + super_traits (super_traits) +{ + trait_substs.clear (); + trait_substs.reserve (substs.size ()); + for (const auto &p : substs) + trait_substs.push_back (p.clone ()); +} + +TraitReference::TraitReference (TraitReference const &other) + : hir_trait_ref (other.hir_trait_ref), item_refs (other.item_refs), + super_traits (other.super_traits) +{ + trait_substs.clear (); + trait_substs.reserve (other.trait_substs.size ()); + for (const auto &p : other.trait_substs) + trait_substs.push_back (p.clone ()); +} + +TraitReference & +TraitReference::operator= (TraitReference const &other) +{ + hir_trait_ref = other.hir_trait_ref; + item_refs = other.item_refs; + super_traits = other.super_traits; + + trait_substs.clear (); + trait_substs.reserve (other.trait_substs.size ()); + for (const auto &p : other.trait_substs) + trait_substs.push_back (p.clone ()); + + return *this; +} + +bool +TraitReference::is_error () const +{ + return hir_trait_ref == nullptr; +} + +Location +TraitReference::get_locus () const +{ + return hir_trait_ref->get_locus (); +} + +std::string +TraitReference::get_name () const +{ + rust_assert (!is_error ()); + return hir_trait_ref->get_name (); +} + +std::string +TraitReference::as_string () const +{ + if (is_error ()) + return "<trait-ref-error-node>"; + + std::string item_buf; + for (auto &item : item_refs) + { + item_buf += item.as_string () + ", "; + } + return "HIR Trait: " + get_name () + "->" + + hir_trait_ref->get_mappings ().as_string () + " [" + item_buf + "]"; +} + +const HIR::Trait * +TraitReference::get_hir_trait_ref () const +{ + return hir_trait_ref; +} + +const Analysis::NodeMapping & +TraitReference::get_mappings () const +{ + return hir_trait_ref->get_mappings (); +} + +DefId +TraitReference::get_defid () const +{ + return get_mappings ().get_defid (); +} + +bool +TraitReference::lookup_hir_trait_item (const HIR::TraitItem &item, + TraitItemReference **ref) +{ + return lookup_trait_item (item.trait_identifier (), ref); +} + +bool +TraitReference::lookup_trait_item (const std::string &ident, + TraitItemReference **ref) +{ + for (auto &item : item_refs) + { + if (ident.compare (item.get_identifier ()) == 0) + { + *ref = &item; + return true; + } + } + return false; +} + +bool +TraitReference::lookup_trait_item_by_type ( + const std::string &ident, TraitItemReference::TraitItemType type, + TraitItemReference **ref) +{ + for (auto &item : item_refs) + { + if (item.get_trait_item_type () != type) + continue; + + if (ident.compare (item.get_identifier ()) == 0) + { + *ref = &item; + return true; + } + } + return false; +} + +bool +TraitReference::lookup_trait_item_by_type ( + const std::string &ident, TraitItemReference::TraitItemType type, + const TraitItemReference **ref) const +{ + for (auto &item : item_refs) + { + if (item.get_trait_item_type () != type) + continue; + + if (ident.compare (item.get_identifier ()) == 0) + { + *ref = &item; + return true; + } + } + return false; +} + +bool +TraitReference::lookup_hir_trait_item (const HIR::TraitItem &item, + const TraitItemReference **ref) const +{ + return lookup_trait_item (item.trait_identifier (), ref); +} + +bool +TraitReference::lookup_trait_item (const std::string &ident, + const TraitItemReference **ref) const +{ + for (auto &item : item_refs) + { + if (ident.compare (item.get_identifier ()) == 0) + { + *ref = &item; + return true; + } + } + + // lookup super traits + for (const auto &super_trait : super_traits) + { + bool found = super_trait->lookup_trait_item (ident, ref); + if (found) + return true; + } + + return false; +} + +const TraitItemReference * +TraitReference::lookup_trait_item (const std::string &ident, + TraitItemReference::TraitItemType type) const +{ + for (auto &item : item_refs) + { + if (item.get_trait_item_type () != type) + continue; + + if (ident.compare (item.get_identifier ()) == 0) + return &item; + } + + // lookup super traits + for (const auto &super_trait : super_traits) + { + const TraitItemReference *res + = super_trait->lookup_trait_item (ident, type); + if (!res->is_error ()) + return res; + } + + return &TraitItemReference::error_node (); +} + +size_t +TraitReference::size () const +{ + return item_refs.size (); +} + +const std::vector<TraitItemReference> & +TraitReference::get_trait_items () const +{ + return item_refs; +} + +void +TraitReference::get_trait_items_and_supers ( + std::vector<const TraitItemReference *> &result) const +{ + for (const auto &item : item_refs) + result.push_back (&item); + + for (const auto &super_trait : super_traits) + super_trait->get_trait_items_and_supers (result); +} + +void +TraitReference::on_resolved () +{ + for (auto &item : item_refs) + { + item.on_resolved (); + } +} + +void +TraitReference::clear_associated_types () const +{ + for (const auto &item : item_refs) + { + bool is_assoc_type = item.get_trait_item_type () + == TraitItemReference::TraitItemType::TYPE; + if (is_assoc_type) + item.associated_type_reset (false); + } +} + +void +TraitReference::clear_associated_type_projections () const +{ + for (const auto &item : item_refs) + { + bool is_assoc_type = item.get_trait_item_type () + == TraitItemReference::TraitItemType::TYPE; + if (is_assoc_type) + item.associated_type_reset (true); + } +} + +bool +TraitReference::is_equal (const TraitReference &other) const +{ + DefId this_id = get_mappings ().get_defid (); + DefId other_id = other.get_mappings ().get_defid (); + return this_id == other_id; +} + +const std::vector<const TraitReference *> +TraitReference::get_super_traits () const +{ + return super_traits; +} + +bool +TraitReference::is_object_safe (bool emit_error, Location locus) const +{ + // https: // doc.rust-lang.org/reference/items/traits.html#object-safety + std::vector<const TraitReference *> non_object_super_traits; + for (auto &item : super_traits) + { + if (!item->is_object_safe (false, Location ())) + non_object_super_traits.push_back (item); + } + + std::vector<const Resolver::TraitItemReference *> non_object_safe_items; + for (auto &item : get_trait_items ()) + { + if (!item.is_object_safe ()) + non_object_safe_items.push_back (&item); + } + + bool is_safe + = non_object_super_traits.empty () && non_object_safe_items.empty (); + if (emit_error && !is_safe) + { + RichLocation r (locus); + for (auto &item : non_object_super_traits) + r.add_range (item->get_locus ()); + for (auto &item : non_object_safe_items) + r.add_range (item->get_locus ()); + + rust_error_at (r, "trait bound is not object safe"); + } + + return is_safe; +} + +bool +TraitReference::trait_has_generics () const +{ + return !trait_substs.empty (); +} + +std::vector<TyTy::SubstitutionParamMapping> +TraitReference::get_trait_substs () const +{ + return trait_substs; +} + +bool +TraitReference::satisfies_bound (const TraitReference &reference) const +{ + if (is_equal (reference)) + return true; + + for (const auto &super_trait : super_traits) + { + if (super_trait->satisfies_bound (reference)) + return true; + } + + return false; +} + +AssociatedImplTrait::AssociatedImplTrait (TraitReference *trait, + HIR::ImplBlock *impl, + TyTy::BaseType *self, + Resolver::TypeCheckContext *context) + : trait (trait), impl (impl), self (self), context (context) +{} + +TraitReference * +AssociatedImplTrait::get_trait () +{ + return trait; +} + +HIR::ImplBlock * +AssociatedImplTrait::get_impl_block () +{ + return impl; +} + +TyTy::BaseType * +AssociatedImplTrait::get_self () +{ + return self; +} +const TyTy::BaseType * +AssociatedImplTrait::get_self () const +{ + return self; +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h new file mode 100644 index 0000000..d20b295 --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -0,0 +1,268 @@ +// Copyright (C) 2021-2023 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_TRAIT_REF_H +#define RUST_HIR_TRAIT_REF_H + +#include "rust-hir-full.h" +#include "rust-hir-type-check-util.h" +#include "rust-tyty-visitor.h" + +namespace Rust { +namespace Resolver { + +// Data Objects for the associated trait items in a structure we can work with +// https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html +class TypeCheckContext; +class TraitItemReference +{ +public: + enum TraitItemType + { + FN, + CONST, + TYPE, + ERROR + }; + + TraitItemReference (std::string identifier, bool optional, TraitItemType type, + HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions, + Location locus); + + TraitItemReference (TraitItemReference const &other); + + TraitItemReference &operator= (TraitItemReference const &other); + + static TraitItemReference error () + { + return TraitItemReference ("", false, ERROR, nullptr, nullptr, {}, + Location ()); + } + + static TraitItemReference &error_node () + { + static TraitItemReference error = TraitItemReference::error (); + return error; + } + + bool is_error () const; + + std::string as_string () const; + + static std::string trait_item_type_as_string (TraitItemType ty) + { + switch (ty) + { + case FN: + return "FN"; + case CONST: + return "CONST"; + case TYPE: + return "TYPE"; + case ERROR: + return "ERROR"; + } + return "ERROR"; + } + + bool is_optional () const; + + std::string get_identifier () const; + + TraitItemType get_trait_item_type () const; + + HIR::TraitItem *get_hir_trait_item () const; + + Location get_locus () const; + + const Analysis::NodeMapping get_mappings () const; + + TyTy::BaseType *get_tyty () const; + + Analysis::NodeMapping get_parent_trait_mappings () const; + + // this is called when the trait is completed resolution and gives the items + // a chance to run their specific type resolution passes. If we call their + // resolution on construction it can lead to a case where the trait being + // resolved recursively trying to resolve the trait itself infinitely since + // the trait will not be stored in its own map yet + void on_resolved (); + + void associated_type_set (TyTy::BaseType *ty) const; + + void associated_type_reset (bool only_projections) const; + + bool is_object_safe () const; + +private: + TyTy::ErrorType *get_error () const; + + TyTy::BaseType *get_type_from_typealias (/*const*/ + HIR::TraitItemType &type) const; + + TyTy::BaseType * + get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const; + + TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const; + + bool is_item_resolved () const; + void resolve_item (HIR::TraitItemType &type); + void resolve_item (HIR::TraitItemConst &constant); + void resolve_item (HIR::TraitItemFunc &func); + + std::string identifier; + bool optional_flag; + TraitItemType type; + HIR::TraitItem *hir_trait_item; + std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions; + Location locus; + + TyTy::BaseType + *self; // this is the implict Self TypeParam required for methods + Resolver::TypeCheckContext *context; +}; + +// this wraps up the HIR::Trait so we can do analysis on it + +class TraitReference +{ +public: + TraitReference (const HIR::Trait *hir_trait_ref, + std::vector<TraitItemReference> item_refs, + std::vector<const TraitReference *> super_traits, + std::vector<TyTy::SubstitutionParamMapping> substs); + + TraitReference (TraitReference const &other); + + TraitReference &operator= (TraitReference const &other); + + TraitReference (TraitReference &&other) = default; + TraitReference &operator= (TraitReference &&other) = default; + + static TraitReference error () + { + return TraitReference (nullptr, {}, {}, {}); + } + + bool is_error () const; + + static TraitReference &error_node () + { + static TraitReference trait_error_node = TraitReference::error (); + return trait_error_node; + } + + Location get_locus () const; + + std::string get_name () const; + + std::string as_string () const; + + const HIR::Trait *get_hir_trait_ref () const; + + const Analysis::NodeMapping &get_mappings () const; + + DefId get_defid () const; + + bool lookup_hir_trait_item (const HIR::TraitItem &item, + TraitItemReference **ref); + + bool lookup_trait_item (const std::string &ident, TraitItemReference **ref); + + bool lookup_trait_item_by_type (const std::string &ident, + TraitItemReference::TraitItemType type, + TraitItemReference **ref); + + bool lookup_trait_item_by_type (const std::string &ident, + TraitItemReference::TraitItemType type, + const TraitItemReference **ref) const; + + bool lookup_hir_trait_item (const HIR::TraitItem &item, + const TraitItemReference **ref) const; + + bool lookup_trait_item (const std::string &ident, + const TraitItemReference **ref) const; + + const TraitItemReference * + lookup_trait_item (const std::string &ident, + TraitItemReference::TraitItemType type) const; + + size_t size () const; + + const std::vector<TraitItemReference> &get_trait_items () const; + + void get_trait_items_and_supers ( + std::vector<const TraitItemReference *> &result) const; + + void on_resolved (); + + void clear_associated_types () const; + + void clear_associated_type_projections () const; + + bool is_equal (const TraitReference &other) const; + + const std::vector<const TraitReference *> get_super_traits () const; + + bool is_object_safe (bool emit_error, Location locus) const; + + bool trait_has_generics () const; + + std::vector<TyTy::SubstitutionParamMapping> get_trait_substs () const; + + bool satisfies_bound (const TraitReference &reference) const; + +private: + const HIR::Trait *hir_trait_ref; + std::vector<TraitItemReference> item_refs; + std::vector<const TraitReference *> super_traits; + std::vector<TyTy::SubstitutionParamMapping> trait_substs; +}; + +class AssociatedImplTrait +{ +public: + AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl, + TyTy::BaseType *self, + Resolver::TypeCheckContext *context); + + TraitReference *get_trait (); + + HIR::ImplBlock *get_impl_block (); + + TyTy::BaseType *get_self (); + const TyTy::BaseType *get_self () const; + + TyTy::BaseType * + setup_associated_types (const TyTy::BaseType *self, + const TyTy::TypeBoundPredicate &bound); + + void reset_associated_types (); + +private: + TraitReference *trait; + HIR::ImplBlock *impl; + TyTy::BaseType *self; + Resolver::TypeCheckContext *context; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_HIR_TRAIT_REF_H diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 2ec9b2e..2d79857 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -22,6 +22,16 @@ namespace Rust { namespace Resolver { +TraitItemReference +ResolveTraitItemToRef::Resolve ( + HIR::TraitItem &item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions) +{ + ResolveTraitItemToRef resolver (self, std::move (substitutions)); + item.accept_vis (resolver); + return std::move (resolver.resolved); +} + void ResolveTraitItemToRef::visit (HIR::TraitItemType &type) { @@ -151,6 +161,9 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) TraitQueryGuard guard (trait_id); TyTy::BaseType *self = nullptr; std::vector<TyTy::SubstitutionParamMapping> substitutions; + + // FIXME + // this should use the resolve_generic_params like everywhere else for (auto &generic_param : trait_reference->get_generic_params ()) { switch (generic_param.get ()->get_kind ()) @@ -172,7 +185,11 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) if (typaram.get_type_representation ().compare ("Self") == 0) { - self = param_type; + rust_assert (param_type->get_kind () == TyTy::TypeKind::PARAM); + TyTy::ParamType *p + = static_cast<TyTy::ParamType *> (param_type); + p->set_implicit_self_trait (); + self = p; } } break; @@ -355,7 +372,7 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) const } void -TraitItemReference::associated_type_reset () const +TraitItemReference::associated_type_reset (bool only_projections) const { rust_assert (get_trait_item_type () == TraitItemType::TYPE); @@ -364,16 +381,27 @@ TraitItemReference::associated_type_reset () const TyTy::PlaceholderType *placeholder = static_cast<TyTy::PlaceholderType *> (item_ty); - placeholder->clear_associated_type (); + if (!only_projections) + { + placeholder->clear_associated_type (); + } + else + { + if (!placeholder->can_resolve ()) + return; + + const TyTy::BaseType *r = placeholder->resolve (); + if (r->get_kind () == TyTy::TypeKind::PROJECTION) + { + placeholder->clear_associated_type (); + } + } } -void +TyTy::BaseType * AssociatedImplTrait::setup_associated_types ( const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound) { - if (!bound.contains_associated_types ()) - return; - // compute the constrained impl block generic arguments based on self and the // higher ranked trait bound TyTy::BaseType *receiver = self->clone (); @@ -441,8 +469,8 @@ AssociatedImplTrait::setup_associated_types ( param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref (); }; - TyTy::SubstitutionArgumentMappings infer_arguments (std::move (args), locus, - param_subst_cb); + TyTy::SubstitutionArgumentMappings infer_arguments (std::move (args), {}, + locus, param_subst_cb); TyTy::BaseType *impl_self_infer = (associated_self->needs_generic_substitutions ()) ? SubstMapperInternal::Resolve (associated_self, infer_arguments) @@ -476,6 +504,7 @@ AssociatedImplTrait::setup_associated_types ( TyTy::TyWithLocation (receiver), TyTy::TyWithLocation (impl_self_infer), impl_predicate.get_locus ()); rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); + TyTy::BaseType *self_result = result; // unify the bounds arguments std::vector<TyTy::BaseType *> hrtb_bound_arguments; @@ -489,8 +518,9 @@ AssociatedImplTrait::setup_associated_types ( hrtb_bound_arguments.push_back (r); } - rust_assert (impl_trait_predicate_args.size () - == hrtb_bound_arguments.size ()); + if (impl_trait_predicate_args.size () != hrtb_bound_arguments.size ()) + return self_result; + for (size_t i = 0; i < impl_trait_predicate_args.size (); i++) { TyTy::BaseType *a = impl_trait_predicate_args.at (i); @@ -521,7 +551,7 @@ AssociatedImplTrait::setup_associated_types ( } TyTy::SubstitutionArgumentMappings associated_type_args ( - std::move (associated_arguments), locus); + std::move (associated_arguments), {}, locus); ImplTypeIterator iter (*impl, [&] (HIR::TypeAlias &type) { TraitItemReference *resolved_trait_item = nullptr; @@ -543,6 +573,8 @@ AssociatedImplTrait::setup_associated_types ( resolved_trait_item->associated_type_set (substituted); }); iter.go (); + + return self_result; } void @@ -593,27 +625,5 @@ TraitItemReference::is_object_safe () const return false; } -// rust-hir-path-probe.h - -void -PathProbeImplTrait::process_trait_impl_items_for_candidates () -{ - mappings->iterate_impl_items ( - [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { - // just need to check if this is an impl block for this trait the next - // function checks the receiver - if (!impl->has_trait_ref ()) - return true; - - TraitReference *resolved - = TraitResolver::Lookup (*(impl->get_trait_ref ().get ())); - if (!trait_reference->is_equal (*resolved)) - return true; - - process_impl_item_candidate (id, item, impl); - return true; - }); -} - } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index ca23d48..da8e2c0 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -19,9 +19,7 @@ #ifndef RUST_HIR_TRAIT_RESOLVE_H #define RUST_HIR_TRAIT_RESOLVE_H -#include "rust-hir-type-check-base.h" #include "rust-hir-type-check-type.h" -#include "rust-hir-trait-ref.h" namespace Rust { namespace Resolver { @@ -32,12 +30,7 @@ class ResolveTraitItemToRef : public TypeCheckBase, public: static TraitItemReference Resolve (HIR::TraitItem &item, TyTy::BaseType *self, - std::vector<TyTy::SubstitutionParamMapping> substitutions) - { - ResolveTraitItemToRef resolver (self, std::move (substitutions)); - item.accept_vis (resolver); - return std::move (resolver.resolved); - } + std::vector<TyTy::SubstitutionParamMapping> substitutions); void visit (HIR::TraitItemType &type) override; diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index 4e8c583..628bba5 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -30,42 +30,18 @@ class TypeBoundsProbe : public TypeCheckBase { public: static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> - Probe (const TyTy::BaseType *receiver) - { - TypeBoundsProbe probe (receiver); - probe.scan (); - return probe.trait_references; - } + Probe (const TyTy::BaseType *receiver); static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver, - TraitReference *ref) - { - for (auto &bound : receiver->get_specified_bounds ()) - { - const TraitReference *b = bound.get (); - if (b->is_equal (*ref)) - return true; - } - - std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds - = Probe (receiver); - for (auto &bound : bounds) - { - const TraitReference *b = bound.first; - if (b->is_equal (*ref)) - return true; - } - - return false; - } + TraitReference *ref); private: void scan (); + void assemble_sized_builtin (); + void assemble_builtin_candidate (Analysis::RustLangItem::ItemType item); private: - TypeBoundsProbe (const TyTy::BaseType *receiver) - : TypeCheckBase (), receiver (receiver) - {} + TypeBoundsProbe (const TyTy::BaseType *receiver); const TyTy::BaseType *receiver; std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references; diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 85826ae..e302e27 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -22,6 +22,7 @@ #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-implitem.h" #include "rust-coercion.h" +#include "rust-unify.h" #include "rust-casts.h" namespace Rust { @@ -359,18 +360,8 @@ TypeCheckBase::unify_site (HirId id, TyTy::TyWithLocation lhs, rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id, expected->debug_str ().c_str (), expr->debug_str ().c_str ()); - TyTy::BaseType *unified = expected->unify (expr); - if (unified->get_kind () == TyTy::TypeKind::ERROR) - { - RichLocation r (unify_locus); - r.add_range (lhs.get_locus ()); - r.add_range (rhs.get_locus ()); - rust_error_at (r, "expected %<%s%> got %<%s%>", - expected->get_name ().c_str (), - expr->get_name ().c_str ()); - } - - return unified; + return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/, + true /*emit_error*/); } TyTy::BaseType * @@ -492,78 +483,5 @@ TypeCheckBase::resolve_generic_params ( } } -bool -TypeCheckBase::query_type (HirId reference, TyTy::BaseType **result) -{ - if (context->query_in_progress (reference)) - return false; - - if (context->lookup_type (reference, result)) - return true; - - context->insert_query (reference); - - HIR::Item *item = mappings->lookup_hir_item (reference); - if (item != nullptr) - { - rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference); - *result = TypeCheckItem::Resolve (*item); - context->query_completed (reference); - return true; - } - - HirId parent_impl_id = UNKNOWN_HIRID; - HIR::ImplItem *impl_item - = mappings->lookup_hir_implitem (reference, &parent_impl_id); - if (impl_item != nullptr) - { - HIR::ImplBlock *impl_block - = mappings->lookup_hir_impl_block (parent_impl_id); - rust_assert (impl_block != nullptr); - - // found an impl item - rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to", - reference); - - *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item); - context->query_completed (reference); - return true; - } - - // is it an impl_type? - HIR::ImplBlock *impl_block_by_type = nullptr; - bool found_impl_block_type - = mappings->lookup_impl_block_type (reference, &impl_block_by_type); - if (found_impl_block_type) - { - *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type); - context->query_completed (reference); - return true; - } - - // is it an extern item? - HirId parent_extern_block_id = UNKNOWN_HIRID; - HIR::ExternalItem *extern_item - = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id); - if (extern_item != nullptr) - { - HIR::ExternBlock *block - = mappings->lookup_hir_extern_block (parent_extern_block_id); - rust_assert (block != nullptr); - - *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block); - context->query_completed (reference); - return true; - } - - // more? - Location possible_locus = mappings->lookup_location (reference); - rust_debug_loc (possible_locus, "query system failed to resolve: [%u]", - reference); - context->query_completed (reference); - - return false; -} - } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 3350143..b8ff2cf 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -69,8 +69,6 @@ protected: const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions); - bool query_type (HirId reference, TyTy::BaseType **result); - Analysis::Mappings *mappings; Resolver *resolver; TypeCheckContext *context; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 5c43cc8..d4eea7a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -618,7 +618,8 @@ TypeCheckExpr::visit (HIR::RangeFromToExpr &expr) const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0); subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified)); - TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ()); + TyTy::SubstitutionArgumentMappings subst (subst_mappings, {}, + expr.get_locus ()); infered = SubstMapperInternal::Resolve (adt, subst); } @@ -664,7 +665,8 @@ TypeCheckExpr::visit (HIR::RangeFromExpr &expr) const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0); subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty)); - TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ()); + TyTy::SubstitutionArgumentMappings subst (subst_mappings, {}, + expr.get_locus ()); infered = SubstMapperInternal::Resolve (adt, subst); } @@ -709,7 +711,8 @@ TypeCheckExpr::visit (HIR::RangeToExpr &expr) const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0); subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty)); - TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ()); + TyTy::SubstitutionArgumentMappings subst (subst_mappings, {}, + expr.get_locus ()); infered = SubstMapperInternal::Resolve (adt, subst); } @@ -792,7 +795,8 @@ TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr) const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0); subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified)); - TyTy::SubstitutionArgumentMappings subst (subst_mappings, expr.get_locus ()); + TyTy::SubstitutionArgumentMappings subst (subst_mappings, {}, + expr.get_locus ()); infered = SubstMapperInternal::Resolve (adt, subst); } @@ -1091,6 +1095,7 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) return; } + fn->prepare_higher_ranked_bounds (); auto root = receiver_tyty->get_root (); if (root->get_kind () == TyTy::TypeKind::ADT) { @@ -1655,6 +1660,11 @@ TypeCheckExpr::resolve_operator_overload ( TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup); rust_assert (fn->is_method ()); + fn->prepare_higher_ranked_bounds (); + rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}", + candidate.candidate.ty->get_ref (), + candidate.candidate.ty->debug_str ().c_str ()); + auto root = lhs->get_root (); if (root->get_kind () == TyTy::TypeKind::ADT) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index 6f1fd41..9d9b294 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -379,16 +379,36 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, if (associated_impl_block != nullptr) { - // get the type of the parent Self - HirId impl_ty_id - = associated_impl_block->get_type ()->get_mappings ().get_hirid (); + // associated types + HirId impl_block_id + = associated_impl_block->get_mappings ().get_hirid (); + + AssociatedImplTrait *associated = nullptr; + bool found_impl_trait + = context->lookup_associated_trait_impl (impl_block_id, + &associated); TyTy::BaseType *impl_block_ty = nullptr; - bool ok = query_type (impl_ty_id, &impl_block_ty); - rust_assert (ok); + if (found_impl_trait) + { + TyTy::TypeBoundPredicate predicate (*associated->get_trait (), + seg.get_locus ()); + impl_block_ty + = associated->setup_associated_types (prev_segment, predicate); + } + else + { + // get the type of the parent Self + HirId impl_ty_id = associated_impl_block->get_type () + ->get_mappings () + .get_hirid (); - if (impl_block_ty->needs_generic_substitutions ()) - impl_block_ty - = SubstMapper::InferSubst (impl_block_ty, seg.get_locus ()); + bool ok = query_type (impl_ty_id, &impl_block_ty); + rust_assert (ok); + + if (impl_block_ty->needs_generic_substitutions ()) + impl_block_ty + = SubstMapper::InferSubst (impl_block_ty, seg.get_locus ()); + } prev_segment = unify_site (seg.get_mappings ().get_hirid (), TyTy::TyWithLocation (prev_segment), diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index b017a85..fd4814c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -387,13 +387,6 @@ TypeCheckPattern::visit (HIR::IdentifierPattern &) } void -TypeCheckPattern::visit (HIR::GroupedPattern &) -{ - // TODO - gcc_unreachable (); -} - -void TypeCheckPattern::visit (HIR::QualifiedPathInExpression &) { // TODO diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.h b/gcc/rust/typecheck/rust-hir-type-check-pattern.h index bdfc907..e755007 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.h +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.h @@ -39,7 +39,6 @@ public: void visit (HIR::LiteralPattern &pattern) override; void visit (HIR::RangePattern &pattern) override; void visit (HIR::IdentifierPattern &pattern) override; - void visit (HIR::GroupedPattern &pattern) override; void visit (HIR::QualifiedPathInExpression &pattern) override; void visit (HIR::ReferencePattern &pattern) override; void visit (HIR::SlicePattern &pattern) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc index 437782e..956249a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -82,7 +82,7 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) { infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); - const HIR::Pattern &stmt_pattern = *stmt.get_pattern (); + HIR::Pattern &stmt_pattern = *stmt.get_pattern (); TyTy::BaseType *init_expr_ty = nullptr; Location init_expr_locus; if (stmt.has_init_expr ()) @@ -111,27 +111,25 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) TyTy::TyWithLocation (specified_ty, specified_ty_locus), TyTy::TyWithLocation (init_expr_ty, init_expr_locus), stmt.get_locus ()); - context->insert_type (stmt_pattern.get_pattern_mappings (), specified_ty); + TypeCheckPattern::Resolve (&stmt_pattern, specified_ty); } else { // let x:i32; if (specified_ty != nullptr) { - context->insert_type (stmt_pattern.get_pattern_mappings (), - specified_ty); + TypeCheckPattern::Resolve (&stmt_pattern, specified_ty); } // let x = 123; else if (init_expr_ty != nullptr) { - context->insert_type (stmt_pattern.get_pattern_mappings (), - init_expr_ty); + TypeCheckPattern::Resolve (&stmt_pattern, init_expr_ty); } // let x; else { - context->insert_type ( - stmt_pattern.get_pattern_mappings (), + TypeCheckPattern::Resolve ( + &stmt_pattern, new TyTy::InferType ( stmt_pattern.get_pattern_mappings ().get_hirid (), TyTy::InferType::InferTypeKind::GENERAL, stmt.get_locus ())); diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index adec2f9..6d4b9b8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -19,10 +19,11 @@ #ifndef RUST_HIR_TYPE_CHECK #define RUST_HIR_TYPE_CHECK +#include "rust-type-util.h" #include "rust-hir-full-decls.h" #include "rust-hir-map.h" #include "rust-tyty.h" -#include "rust-hir-trait-ref.h" +#include "rust-hir-trait-reference.h" #include "rust-autoderef.h" namespace Rust { @@ -38,37 +39,17 @@ public: TRAIT_ITEM, }; - TypeCheckContextItem (HIR::Function *item) - : type (ItemType::ITEM), item (item) - {} + TypeCheckContextItem (HIR::Function *item); + TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item); + TypeCheckContextItem (HIR::TraitItemFunc *trait_item); - TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item) - : type (ItemType::IMPL_ITEM), item (impl_block, item) - {} + ItemType get_type () const; - TypeCheckContextItem (HIR::TraitItemFunc *trait_item) - : type (ItemType::TRAIT_ITEM), item (trait_item) - {} + HIR::Function *get_item (); - ItemType get_type () const { return type; } + std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item (); - HIR::Function *get_item () - { - rust_assert (get_type () == ItemType::ITEM); - return item.item; - } - - std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item () - { - rust_assert (get_type () == ItemType::IMPL_ITEM); - return item.impl_item; - }; - - HIR::TraitItemFunc *get_trait_item () - { - rust_assert (get_type () == ItemType::TRAIT_ITEM); - return item.trait_item; - } + HIR::TraitItemFunc *get_trait_item (); TyTy::FnType *get_context_type (); @@ -79,13 +60,9 @@ private: std::pair<HIR::ImplBlock *, HIR::Function *> impl_item; HIR::TraitItemFunc *trait_item; - Item (HIR::Function *item) : item (item) {} - - Item (HIR::ImplBlock *impl_block, HIR::Function *item) - : impl_item ({impl_block, item}) - {} - - Item (HIR::TraitItemFunc *trait_item) : trait_item (trait_item) {} + Item (HIR::Function *item); + Item (HIR::ImplBlock *impl_block, HIR::Function *item); + Item (HIR::TraitItemFunc *trait_item); }; ItemType type; @@ -118,283 +95,71 @@ public: void push_return_type (TypeCheckContextItem item, TyTy::BaseType *return_type); void pop_return_type (); + void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb); - void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb) - { - for (auto it = resolved.begin (); it != resolved.end (); it++) - { - if (!cb (it->first, it->second)) - return; - } - } - - bool have_loop_context () const { return !loop_type_stack.empty (); } - - void push_new_loop_context (HirId id, Location locus) - { - TyTy::BaseType *infer_var - = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL, - locus); - loop_type_stack.push_back (infer_var); - } - - void push_new_while_loop_context (HirId id) - { - TyTy::BaseType *infer_var = new TyTy::ErrorType (id); - loop_type_stack.push_back (infer_var); - } - - TyTy::BaseType *peek_loop_context () { return loop_type_stack.back (); } - - TyTy::BaseType *pop_loop_context () - { - auto back = peek_loop_context (); - loop_type_stack.pop_back (); - return back; - } - - void swap_head_loop_context (TyTy::BaseType *val) - { - loop_type_stack.pop_back (); - loop_type_stack.push_back (val); - } - - void insert_trait_reference (DefId id, TraitReference &&ref) - { - rust_assert (trait_context.find (id) == trait_context.end ()); - trait_context.emplace (id, std::move (ref)); - } - - bool lookup_trait_reference (DefId id, TraitReference **ref) - { - auto it = trait_context.find (id); - if (it == trait_context.end ()) - return false; + bool have_loop_context () const; + void push_new_loop_context (HirId id, Location locus); + void push_new_while_loop_context (HirId id); + TyTy::BaseType *peek_loop_context (); + TyTy::BaseType *pop_loop_context (); - *ref = &it->second; - return true; - } - - void insert_receiver (HirId id, TyTy::BaseType *t) - { - receiver_context[id] = t; - } + void swap_head_loop_context (TyTy::BaseType *val); - bool lookup_receiver (HirId id, TyTy::BaseType **ref) - { - auto it = receiver_context.find (id); - if (it == receiver_context.end ()) - return false; + void insert_trait_reference (DefId id, TraitReference &&ref); + bool lookup_trait_reference (DefId id, TraitReference **ref); - *ref = it->second; - return true; - } + void insert_receiver (HirId id, TyTy::BaseType *t); + bool lookup_receiver (HirId id, TyTy::BaseType **ref); - void insert_associated_trait_impl (HirId id, AssociatedImplTrait &&associated) - { - rust_assert (associated_impl_traits.find (id) - == associated_impl_traits.end ()); - associated_impl_traits.emplace (id, std::move (associated)); - } + void insert_associated_trait_impl (HirId id, + AssociatedImplTrait &&associated); + bool lookup_associated_trait_impl (HirId id, + AssociatedImplTrait **associated); - bool lookup_associated_trait_impl (HirId id, AssociatedImplTrait **associated) - { - auto it = associated_impl_traits.find (id); - if (it == associated_impl_traits.end ()) - return false; - - *associated = &it->second; - return true; - } - - void insert_associated_type_mapping (HirId id, HirId mapping) - { - associated_type_mappings[id] = mapping; - } - - void clear_associated_type_mapping (HirId id) - { - auto it = associated_type_mappings.find (id); - if (it != associated_type_mappings.end ()) - associated_type_mappings.erase (it); - } + void insert_associated_type_mapping (HirId id, HirId mapping); + void clear_associated_type_mapping (HirId id); // lookup any associated type mappings, the out parameter of mapping is // allowed to be nullptr which allows this interface to do a simple does exist // check - bool lookup_associated_type_mapping (HirId id, HirId *mapping) - { - auto it = associated_type_mappings.find (id); - if (it == associated_type_mappings.end ()) - return false; - - if (mapping != nullptr) - *mapping = it->second; - - return true; - } + bool lookup_associated_type_mapping (HirId id, HirId *mapping); void insert_associated_impl_mapping (HirId trait_id, const TyTy::BaseType *impl_type, - HirId impl_id) - { - auto it = associated_traits_to_impls.find (trait_id); - if (it == associated_traits_to_impls.end ()) - { - associated_traits_to_impls[trait_id] = {}; - } - - associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id}); - } - + HirId impl_id); bool lookup_associated_impl_mapping_for_self (HirId trait_id, const TyTy::BaseType *self, - HirId *mapping) - { - auto it = associated_traits_to_impls.find (trait_id); - if (it == associated_traits_to_impls.end ()) - return false; - - for (auto &item : it->second) - { - if (item.first->can_eq (self, false)) - { - *mapping = item.second; - return true; - } - } - return false; - } + HirId *mapping); void insert_autoderef_mappings (HirId id, - std::vector<Adjustment> &&adjustments) - { - rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ()); - autoderef_mappings.emplace (id, std::move (adjustments)); - } - + std::vector<Adjustment> &&adjustments); bool lookup_autoderef_mappings (HirId id, - std::vector<Adjustment> **adjustments) - { - auto it = autoderef_mappings.find (id); - if (it == autoderef_mappings.end ()) - return false; - - *adjustments = &it->second; - return true; - } + std::vector<Adjustment> **adjustments); void insert_cast_autoderef_mappings (HirId id, - std::vector<Adjustment> &&adjustments) - { - rust_assert (cast_autoderef_mappings.find (id) - == cast_autoderef_mappings.end ()); - cast_autoderef_mappings.emplace (id, std::move (adjustments)); - } - + std::vector<Adjustment> &&adjustments); bool lookup_cast_autoderef_mappings (HirId id, - std::vector<Adjustment> **adjustments) - { - auto it = cast_autoderef_mappings.find (id); - if (it == cast_autoderef_mappings.end ()) - return false; + std::vector<Adjustment> **adjustments); - *adjustments = &it->second; - return true; - } + void insert_variant_definition (HirId id, HirId variant); + bool lookup_variant_definition (HirId id, HirId *variant); - void insert_variant_definition (HirId id, HirId variant) - { - auto it = variants.find (id); - rust_assert (it == variants.end ()); + void insert_operator_overload (HirId id, TyTy::FnType *call_site); + bool lookup_operator_overload (HirId id, TyTy::FnType **call); - variants[id] = variant; - } + void insert_unconstrained_check_marker (HirId id, bool status); + bool have_checked_for_unconstrained (HirId id, bool *result); - bool lookup_variant_definition (HirId id, HirId *variant) - { - auto it = variants.find (id); - if (it == variants.end ()) - return false; + void insert_resolved_predicate (HirId id, TyTy::TypeBoundPredicate predicate); + bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result); - *variant = it->second; - return true; - } - - void insert_operator_overload (HirId id, TyTy::FnType *call_site) - { - auto it = operator_overloads.find (id); - rust_assert (it == operator_overloads.end ()); - - operator_overloads[id] = call_site; - } - - bool lookup_operator_overload (HirId id, TyTy::FnType **call) - { - auto it = operator_overloads.find (id); - if (it == operator_overloads.end ()) - return false; - - *call = it->second; - return true; - } + void insert_query (HirId id); + void query_completed (HirId id); + bool query_in_progress (HirId id) const; - void insert_unconstrained_check_marker (HirId id, bool status) - { - unconstrained[id] = status; - } - - bool have_checked_for_unconstrained (HirId id, bool *result) - { - auto it = unconstrained.find (id); - bool found = it != unconstrained.end (); - if (!found) - return false; - - *result = it->second; - return true; - } - - void insert_resolved_predicate (HirId id, TyTy::TypeBoundPredicate predicate) - { - auto it = predicates.find (id); - rust_assert (it == predicates.end ()); - - predicates.insert ({id, predicate}); - } - - bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result) - { - auto it = predicates.find (id); - bool found = it != predicates.end (); - if (!found) - return false; - - *result = it->second; - return true; - } - - void insert_query (HirId id) { querys_in_progress.insert (id); } - - void query_completed (HirId id) { querys_in_progress.erase (id); } - - bool query_in_progress (HirId id) const - { - return querys_in_progress.find (id) != querys_in_progress.end (); - } - - void insert_trait_query (DefId id) { trait_queries_in_progress.insert (id); } - - void trait_query_completed (DefId id) - { - trait_queries_in_progress.erase (id); - } - - bool trait_query_in_progress (DefId id) const - { - return trait_queries_in_progress.find (id) - != trait_queries_in_progress.end (); - } + void insert_trait_query (DefId id); + void trait_query_completed (DefId id); + bool trait_query_in_progress (DefId id) const; private: TypeCheckContext (); diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index e1d9888..dc93857 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.cc +++ b/gcc/rust/typecheck/rust-substitution-mapper.cc @@ -22,6 +22,116 @@ namespace Rust { namespace Resolver { +SubstMapper::SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus) + : resolved (new TyTy::ErrorType (ref)), generics (generics), locus (locus) +{} + +TyTy::BaseType * +SubstMapper::Resolve (TyTy::BaseType *base, Location locus, + HIR::GenericArgs *generics) +{ + SubstMapper mapper (base->get_ref (), generics, locus); + base->accept_vis (mapper); + rust_assert (mapper.resolved != nullptr); + return mapper.resolved; +} + +TyTy::BaseType * +SubstMapper::InferSubst (TyTy::BaseType *base, Location locus) +{ + return SubstMapper::Resolve (base, locus, nullptr); +} + +bool +SubstMapper::have_generic_args () const +{ + return generics != nullptr; +} + +void +SubstMapper::visit (TyTy::FnType &type) +{ + TyTy::FnType *concrete = nullptr; + if (!have_generic_args ()) + { + TyTy::BaseType *substs = type.infer_substitions (locus); + rust_assert (substs->get_kind () == TyTy::TypeKind::FNDEF); + concrete = static_cast<TyTy::FnType *> (substs); + } + else + { + TyTy::SubstitutionArgumentMappings mappings + = type.get_mappings_from_generic_args (*generics); + if (mappings.is_error ()) + return; + + concrete = type.handle_substitions (mappings); + } + + if (concrete != nullptr) + resolved = concrete; +} + +void +SubstMapper::visit (TyTy::ADTType &type) +{ + TyTy::ADTType *concrete = nullptr; + if (!have_generic_args ()) + { + TyTy::BaseType *substs = type.infer_substitions (locus); + rust_assert (substs->get_kind () == TyTy::TypeKind::ADT); + concrete = static_cast<TyTy::ADTType *> (substs); + } + else + { + TyTy::SubstitutionArgumentMappings mappings + = type.get_mappings_from_generic_args (*generics); + if (mappings.is_error ()) + return; + + concrete = type.handle_substitions (mappings); + } + + if (concrete != nullptr) + resolved = concrete; +} + +void +SubstMapper::visit (TyTy::PlaceholderType &type) +{ + rust_assert (type.can_resolve ()); + resolved = SubstMapper::Resolve (type.resolve (), locus, generics); +} + +void +SubstMapper::visit (TyTy::ProjectionType &type) +{ + TyTy::ProjectionType *concrete = nullptr; + if (!have_generic_args ()) + { + TyTy::BaseType *substs = type.infer_substitions (locus); + rust_assert (substs->get_kind () == TyTy::TypeKind::PROJECTION); + concrete = static_cast<TyTy::ProjectionType *> (substs); + } + else + { + TyTy::SubstitutionArgumentMappings mappings + = type.get_mappings_from_generic_args (*generics); + if (mappings.is_error ()) + return; + + concrete = type.handle_substitions (mappings); + } + + if (concrete != nullptr) + resolved = concrete; +} + +SubstMapperInternal::SubstMapperInternal ( + HirId ref, TyTy::SubstitutionArgumentMappings &mappings) + : resolved (new TyTy::ErrorType (ref)), mappings (mappings) +{} + TyTy::BaseType * SubstMapperInternal::Resolve (TyTy::BaseType *base, TyTy::SubstitutionArgumentMappings &mappings) @@ -73,5 +183,238 @@ SubstMapperInternal::mappings_are_bound ( return false; } +void +SubstMapperInternal::visit (TyTy::FnType &type) +{ + TyTy::SubstitutionArgumentMappings adjusted + = type.adjust_mappings_for_this (mappings); + if (adjusted.is_error ()) + return; + + TyTy::BaseType *concrete = type.handle_substitions (adjusted); + if (concrete != nullptr) + resolved = concrete; +} + +void +SubstMapperInternal::visit (TyTy::ADTType &type) +{ + TyTy::SubstitutionArgumentMappings adjusted + = type.adjust_mappings_for_this (mappings); + if (adjusted.is_error ()) + return; + + TyTy::BaseType *concrete = type.handle_substitions (adjusted); + if (concrete != nullptr) + resolved = concrete; +} + +// these don't support generic arguments but might contain a type param +void +SubstMapperInternal::visit (TyTy::TupleType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::ReferenceType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::PointerType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::ParamType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::PlaceholderType &type) +{ + rust_assert (type.can_resolve ()); + if (mappings.trait_item_mode ()) + { + resolved = type.resolve (); + } + else + { + resolved = SubstMapperInternal::Resolve (type.resolve (), mappings); + } +} + +void +SubstMapperInternal::visit (TyTy::ProjectionType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::ClosureType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::ArrayType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void +SubstMapperInternal::visit (TyTy::SliceType &type) +{ + resolved = type.handle_substitions (mappings); +} + +// nothing to do for these +void +SubstMapperInternal::visit (TyTy::InferType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::FnPtr &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::BoolType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::IntType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::UintType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::FloatType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::USizeType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::ISizeType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::ErrorType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::CharType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::StrType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::NeverType &type) +{ + resolved = type.clone (); +} +void +SubstMapperInternal::visit (TyTy::DynamicObjectType &type) +{ + resolved = type.clone (); +} + +// SubstMapperFromExisting + +SubstMapperFromExisting::SubstMapperFromExisting (TyTy::BaseType *concrete, + TyTy::BaseType *receiver) + : concrete (concrete), receiver (receiver), resolved (nullptr) +{} + +TyTy::BaseType * +SubstMapperFromExisting::Resolve (TyTy::BaseType *concrete, + TyTy::BaseType *receiver) +{ + rust_assert (concrete->get_kind () == receiver->get_kind ()); + + SubstMapperFromExisting mapper (concrete, receiver); + concrete->accept_vis (mapper); + return mapper.resolved; +} + +void +SubstMapperFromExisting::visit (TyTy::FnType &type) +{ + rust_assert (type.was_substituted ()); + + TyTy::FnType *to_sub = static_cast<TyTy::FnType *> (receiver); + resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); +} + +void +SubstMapperFromExisting::visit (TyTy::ADTType &type) +{ + rust_assert (type.was_substituted ()); + + TyTy::ADTType *to_sub = static_cast<TyTy::ADTType *> (receiver); + resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); +} + +void +SubstMapperFromExisting::visit (TyTy::ClosureType &type) +{ + rust_assert (type.was_substituted ()); + + TyTy::ClosureType *to_sub = static_cast<TyTy::ClosureType *> (receiver); + resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); +} + +// GetUsedSubstArgs + +GetUsedSubstArgs::GetUsedSubstArgs () + : args (TyTy::SubstitutionArgumentMappings::error ()) +{} + +TyTy::SubstitutionArgumentMappings +GetUsedSubstArgs::From (const TyTy::BaseType *from) +{ + GetUsedSubstArgs mapper; + from->accept_vis (mapper); + return mapper.args; +} + +void +GetUsedSubstArgs::visit (const TyTy::FnType &type) +{ + args = type.get_substitution_arguments (); +} + +void +GetUsedSubstArgs::visit (const TyTy::ADTType &type) +{ + args = type.get_substitution_arguments (); +} + +void +GetUsedSubstArgs::visit (const TyTy::ClosureType &type) +{ + args = type.get_substitution_arguments (); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index 995d9c8..43b80b3 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -29,95 +29,16 @@ class SubstMapper : public TyTy::TyVisitor { public: static TyTy::BaseType *Resolve (TyTy::BaseType *base, Location locus, - HIR::GenericArgs *generics = nullptr) - { - SubstMapper mapper (base->get_ref (), generics, locus); - base->accept_vis (mapper); - rust_assert (mapper.resolved != nullptr); - return mapper.resolved; - } + HIR::GenericArgs *generics = nullptr); - static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus) - { - return SubstMapper::Resolve (base, locus, nullptr); - } + static TyTy::BaseType *InferSubst (TyTy::BaseType *base, Location locus); - bool have_generic_args () const { return generics != nullptr; } + bool have_generic_args () const; - void visit (TyTy::FnType &type) override - { - TyTy::FnType *concrete = nullptr; - if (!have_generic_args ()) - { - TyTy::BaseType *substs = type.infer_substitions (locus); - rust_assert (substs->get_kind () == TyTy::TypeKind::FNDEF); - concrete = static_cast<TyTy::FnType *> (substs); - } - else - { - TyTy::SubstitutionArgumentMappings mappings - = type.get_mappings_from_generic_args (*generics); - if (mappings.is_error ()) - return; - - concrete = type.handle_substitions (mappings); - } - - if (concrete != nullptr) - resolved = concrete; - } - - void visit (TyTy::ADTType &type) override - { - TyTy::ADTType *concrete = nullptr; - if (!have_generic_args ()) - { - TyTy::BaseType *substs = type.infer_substitions (locus); - rust_assert (substs->get_kind () == TyTy::TypeKind::ADT); - concrete = static_cast<TyTy::ADTType *> (substs); - } - else - { - TyTy::SubstitutionArgumentMappings mappings - = type.get_mappings_from_generic_args (*generics); - if (mappings.is_error ()) - return; - - concrete = type.handle_substitions (mappings); - } - - if (concrete != nullptr) - resolved = concrete; - } - - void visit (TyTy::PlaceholderType &type) override - { - rust_assert (type.can_resolve ()); - resolved = SubstMapper::Resolve (type.resolve (), locus, generics); - } - - void visit (TyTy::ProjectionType &type) override - { - TyTy::ProjectionType *concrete = nullptr; - if (!have_generic_args ()) - { - TyTy::BaseType *substs = type.infer_substitions (locus); - rust_assert (substs->get_kind () == TyTy::TypeKind::PROJECTION); - concrete = static_cast<TyTy::ProjectionType *> (substs); - } - else - { - TyTy::SubstitutionArgumentMappings mappings - = type.get_mappings_from_generic_args (*generics); - if (mappings.is_error ()) - return; - - concrete = type.handle_substitions (mappings); - } - - if (concrete != nullptr) - resolved = concrete; - } + void visit (TyTy::FnType &type) override; + void visit (TyTy::ADTType &type) override; + void visit (TyTy::PlaceholderType &type) override; + void visit (TyTy::ProjectionType &type) override; // nothing to do for these void visit (TyTy::InferType &) override { gcc_unreachable (); } @@ -142,9 +63,7 @@ public: void visit (TyTy::ClosureType &) override { gcc_unreachable (); } private: - SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus) - : resolved (new TyTy::ErrorType (ref)), generics (generics), locus (locus) - {} + SubstMapper (HirId ref, HIR::GenericArgs *generics, Location locus); TyTy::BaseType *resolved; HIR::GenericArgs *generics; @@ -160,106 +79,33 @@ public: static bool mappings_are_bound (TyTy::BaseType *ty, TyTy::SubstitutionArgumentMappings &mappings); - void visit (TyTy::FnType &type) override - { - TyTy::SubstitutionArgumentMappings adjusted - = type.adjust_mappings_for_this (mappings); - if (adjusted.is_error ()) - return; - - TyTy::BaseType *concrete = type.handle_substitions (adjusted); - if (concrete != nullptr) - resolved = concrete; - } - - void visit (TyTy::ADTType &type) override - { - TyTy::SubstitutionArgumentMappings adjusted - = type.adjust_mappings_for_this (mappings); - if (adjusted.is_error ()) - return; - - TyTy::BaseType *concrete = type.handle_substitions (adjusted); - if (concrete != nullptr) - resolved = concrete; - } - - // these don't support generic arguments but might contain a type param - void visit (TyTy::TupleType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::ReferenceType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::PointerType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::ParamType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::PlaceholderType &type) override - { - rust_assert (type.can_resolve ()); - if (mappings.trait_item_mode ()) - { - resolved = type.resolve (); - } - else - { - resolved = SubstMapperInternal::Resolve (type.resolve (), mappings); - } - } - - void visit (TyTy::ProjectionType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::ClosureType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::ArrayType &type) override - { - resolved = type.handle_substitions (mappings); - } - - void visit (TyTy::SliceType &type) override - { - resolved = type.handle_substitions (mappings); - } - - // nothing to do for these - void visit (TyTy::InferType &type) override { resolved = type.clone (); } - void visit (TyTy::FnPtr &type) override { resolved = type.clone (); } - void visit (TyTy::BoolType &type) override { resolved = type.clone (); } - void visit (TyTy::IntType &type) override { resolved = type.clone (); } - void visit (TyTy::UintType &type) override { resolved = type.clone (); } - void visit (TyTy::FloatType &type) override { resolved = type.clone (); } - void visit (TyTy::USizeType &type) override { resolved = type.clone (); } - void visit (TyTy::ISizeType &type) override { resolved = type.clone (); } - void visit (TyTy::ErrorType &type) override { resolved = type.clone (); } - void visit (TyTy::CharType &type) override { resolved = type.clone (); } - void visit (TyTy::StrType &type) override { resolved = type.clone (); } - void visit (TyTy::NeverType &type) override { resolved = type.clone (); } - void visit (TyTy::DynamicObjectType &type) override - { - resolved = type.clone (); - } + void visit (TyTy::FnType &type) override; + void visit (TyTy::ADTType &type) override; + void visit (TyTy::TupleType &type) override; + void visit (TyTy::ReferenceType &type) override; + void visit (TyTy::PointerType &type) override; + void visit (TyTy::ParamType &type) override; + void visit (TyTy::PlaceholderType &type) override; + void visit (TyTy::ProjectionType &type) override; + void visit (TyTy::ClosureType &type) override; + void visit (TyTy::ArrayType &type) override; + void visit (TyTy::SliceType &type) override; + void visit (TyTy::InferType &type) override; + void visit (TyTy::FnPtr &type) override; + void visit (TyTy::BoolType &type) override; + void visit (TyTy::IntType &type) override; + void visit (TyTy::UintType &type) override; + void visit (TyTy::FloatType &type) override; + void visit (TyTy::USizeType &type) override; + void visit (TyTy::ISizeType &type) override; + void visit (TyTy::ErrorType &type) override; + void visit (TyTy::CharType &type) override; + void visit (TyTy::StrType &type) override; + void visit (TyTy::NeverType &type) override; + void visit (TyTy::DynamicObjectType &type) override; private: - SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings) - : resolved (new TyTy::ErrorType (ref)), mappings (mappings) - {} + SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings); TyTy::BaseType *resolved; TyTy::SubstitutionArgumentMappings &mappings; @@ -269,38 +115,11 @@ class SubstMapperFromExisting : public TyTy::TyVisitor { public: static TyTy::BaseType *Resolve (TyTy::BaseType *concrete, - TyTy::BaseType *receiver) - { - rust_assert (concrete->get_kind () == receiver->get_kind ()); - - SubstMapperFromExisting mapper (concrete, receiver); - concrete->accept_vis (mapper); - return mapper.resolved; - } + TyTy::BaseType *receiver); - void visit (TyTy::FnType &type) override - { - rust_assert (type.was_substituted ()); - - TyTy::FnType *to_sub = static_cast<TyTy::FnType *> (receiver); - resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); - } - - void visit (TyTy::ADTType &type) override - { - rust_assert (type.was_substituted ()); - - TyTy::ADTType *to_sub = static_cast<TyTy::ADTType *> (receiver); - resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); - } - - void visit (TyTy::ClosureType &type) override - { - rust_assert (type.was_substituted ()); - - TyTy::ClosureType *to_sub = static_cast<TyTy::ClosureType *> (receiver); - resolved = to_sub->handle_substitions (type.get_substitution_arguments ()); - } + void visit (TyTy::FnType &type) override; + void visit (TyTy::ADTType &type) override; + void visit (TyTy::ClosureType &type) override; void visit (TyTy::InferType &) override { gcc_unreachable (); } void visit (TyTy::TupleType &) override { gcc_unreachable (); } @@ -325,40 +144,21 @@ public: void visit (TyTy::DynamicObjectType &) override { gcc_unreachable (); } private: - SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver) - : concrete (concrete), receiver (receiver), resolved (nullptr) - {} + SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver); TyTy::BaseType *concrete; TyTy::BaseType *receiver; - TyTy::BaseType *resolved; }; class GetUsedSubstArgs : public TyTy::TyConstVisitor { public: - static TyTy::SubstitutionArgumentMappings From (const TyTy::BaseType *from) - { - GetUsedSubstArgs mapper; - from->accept_vis (mapper); - return mapper.args; - } - - void visit (const TyTy::FnType &type) override - { - args = type.get_substitution_arguments (); - } - - void visit (const TyTy::ADTType &type) override - { - args = type.get_substitution_arguments (); - } + static TyTy::SubstitutionArgumentMappings From (const TyTy::BaseType *from); - void visit (const TyTy::ClosureType &type) override - { - args = type.get_substitution_arguments (); - } + void visit (const TyTy::FnType &type) override; + void visit (const TyTy::ADTType &type) override; + void visit (const TyTy::ClosureType &type) override; void visit (const TyTy::InferType &) override {} void visit (const TyTy::TupleType &) override {} @@ -383,7 +183,7 @@ public: void visit (const TyTy::DynamicObjectType &) override {} private: - GetUsedSubstArgs () : args (TyTy::SubstitutionArgumentMappings::error ()) {} + GetUsedSubstArgs (); TyTy::SubstitutionArgumentMappings args; }; diff --git a/gcc/rust/typecheck/rust-tyctx.cc b/gcc/rust/typecheck/rust-tyctx.cc deleted file mode 100644 index 886842b..0000000 --- a/gcc/rust/typecheck/rust-tyctx.cc +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2020-2023 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/>. - -#include "rust-hir-type-check.h" - -namespace Rust { -namespace Resolver { - -TypeCheckContext * -TypeCheckContext::get () -{ - static TypeCheckContext *instance; - if (instance == nullptr) - instance = new TypeCheckContext (); - - return instance; -} - -TypeCheckContext::TypeCheckContext () {} - -TypeCheckContext::~TypeCheckContext () {} - -bool -TypeCheckContext::lookup_builtin (NodeId id, TyTy::BaseType **type) -{ - auto ref_it = node_id_refs.find (id); - if (ref_it == node_id_refs.end ()) - return false; - - auto it = resolved.find (ref_it->second); - if (it == resolved.end ()) - return false; - - *type = it->second; - return true; -} - -bool -TypeCheckContext::lookup_builtin (std::string name, TyTy::BaseType **type) -{ - for (auto &builtin : builtins) - { - if (name.compare (builtin->as_string ()) == 0) - { - *type = builtin.get (); - return true; - } - } - return false; -} - -void -TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type) -{ - node_id_refs[ref] = id; - resolved[id] = type; - builtins.push_back (std::unique_ptr<TyTy::BaseType> (type)); -} - -void -TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings, - TyTy::BaseType *type) -{ - rust_assert (type != nullptr); - NodeId ref = mappings.get_nodeid (); - HirId id = mappings.get_hirid (); - node_id_refs[ref] = id; - resolved[id] = type; -} - -void -TypeCheckContext::insert_implicit_type (TyTy::BaseType *type) -{ - rust_assert (type != nullptr); - resolved[type->get_ref ()] = type; -} - -void -TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type) -{ - rust_assert (type != nullptr); - resolved[id] = type; -} - -bool -TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const -{ - auto it = resolved.find (id); - if (it == resolved.end ()) - return false; - - *type = it->second; - return true; -} - -void -TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id) -{ - rust_assert (node_id_refs.find (ref) == node_id_refs.end ()); - node_id_refs[ref] = id; -} - -bool -TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id) -{ - auto it = node_id_refs.find (ref); - if (it == node_id_refs.end ()) - return false; - - *id = it->second; - return true; -} - -TyTy::BaseType * -TypeCheckContext::peek_return_type () -{ - rust_assert (!return_type_stack.empty ()); - return return_type_stack.back ().second; -} - -void -TypeCheckContext::push_return_type (TypeCheckContextItem item, - TyTy::BaseType *return_type) -{ - return_type_stack.push_back ({std::move (item), return_type}); -} - -void -TypeCheckContext::pop_return_type () -{ - rust_assert (!return_type_stack.empty ()); - return_type_stack.pop_back (); -} - -TypeCheckContextItem & -TypeCheckContext::peek_context () -{ - rust_assert (!return_type_stack.empty ()); - return return_type_stack.back ().first; -} - -// TypeCheckContextItem - -TyTy::FnType * -TypeCheckContextItem::get_context_type () -{ - auto &context = *TypeCheckContext::get (); - - HirId reference = UNKNOWN_HIRID; - switch (get_type ()) - { - case ITEM: - reference = get_item ()->get_mappings ().get_hirid (); - break; - - case IMPL_ITEM: - reference = get_impl_item ().second->get_mappings ().get_hirid (); - break; - - case TRAIT_ITEM: - reference = get_trait_item ()->get_mappings ().get_hirid (); - break; - } - - rust_assert (reference != UNKNOWN_HIRID); - - TyTy::BaseType *lookup = nullptr; - bool ok = context.lookup_type (reference, &lookup); - rust_assert (ok); - rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); - return static_cast<TyTy::FnType *> (lookup); -} - -} // namespace Resolver -} // namespace Rust diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc new file mode 100644 index 0000000..4e38826 --- /dev/null +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -0,0 +1,108 @@ +// Copyright (C) 2020-2022 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/>. + +#include "rust-type-util.h" +#include "rust-diagnostics.h" +#include "rust-hir-type-check.h" +#include "rust-name-resolver.h" +#include "rust-hir-visitor.h" +#include "rust-hir-map.h" +#include "rust-hir-type-check-item.h" +#include "rust-hir-type-check-implitem.h" + +namespace Rust { +namespace Resolver { + +bool +query_type (HirId reference, TyTy::BaseType **result) +{ + Analysis::Mappings *mappings = Analysis::Mappings::get (); + TypeCheckContext *context = TypeCheckContext::get (); + + if (context->query_in_progress (reference)) + return false; + + if (context->lookup_type (reference, result)) + return true; + + context->insert_query (reference); + + HIR::Item *item = mappings->lookup_hir_item (reference); + if (item != nullptr) + { + rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference); + *result = TypeCheckItem::Resolve (*item); + context->query_completed (reference); + return true; + } + + HirId parent_impl_id = UNKNOWN_HIRID; + HIR::ImplItem *impl_item + = mappings->lookup_hir_implitem (reference, &parent_impl_id); + if (impl_item != nullptr) + { + HIR::ImplBlock *impl_block + = mappings->lookup_hir_impl_block (parent_impl_id); + rust_assert (impl_block != nullptr); + + // found an impl item + rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to", + reference); + + *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item); + context->query_completed (reference); + return true; + } + + // is it an impl_type? + HIR::ImplBlock *impl_block_by_type = nullptr; + bool found_impl_block_type + = mappings->lookup_impl_block_type (reference, &impl_block_by_type); + if (found_impl_block_type) + { + *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type); + context->query_completed (reference); + return true; + } + + // is it an extern item? + HirId parent_extern_block_id = UNKNOWN_HIRID; + HIR::ExternalItem *extern_item + = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id); + if (extern_item != nullptr) + { + HIR::ExternBlock *block + = mappings->lookup_hir_extern_block (parent_extern_block_id); + rust_assert (block != nullptr); + + *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block); + context->query_completed (reference); + return true; + } + + // more? + Location possible_locus = mappings->lookup_location (reference); + rust_debug_loc (possible_locus, "query system failed to resolve: [%u]", + reference); + context->query_completed (reference); + + return false; +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-type-util.h b/gcc/rust/typecheck/rust-type-util.h new file mode 100644 index 0000000..a3f9efc --- /dev/null +++ b/gcc/rust/typecheck/rust-type-util.h @@ -0,0 +1,38 @@ +// Copyright (C) 2020-2022 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_TYPE_UTIL +#define RUST_TYPE_UTIL + +#include "rust-mapping-common.h" + +namespace Rust { + +namespace TyTy { +class BaseType; +} + +namespace Resolver { + +extern bool +query_type (HirId reference, TyTy::BaseType **result); + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_TYPE_UTIL diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc new file mode 100644 index 0000000..27ff969 --- /dev/null +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -0,0 +1,569 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Resolver { + +TypeCheckContext * +TypeCheckContext::get () +{ + static TypeCheckContext *instance; + if (instance == nullptr) + instance = new TypeCheckContext (); + + return instance; +} + +TypeCheckContext::TypeCheckContext () {} + +TypeCheckContext::~TypeCheckContext () {} + +bool +TypeCheckContext::lookup_builtin (NodeId id, TyTy::BaseType **type) +{ + auto ref_it = node_id_refs.find (id); + if (ref_it == node_id_refs.end ()) + return false; + + auto it = resolved.find (ref_it->second); + if (it == resolved.end ()) + return false; + + *type = it->second; + return true; +} + +bool +TypeCheckContext::lookup_builtin (std::string name, TyTy::BaseType **type) +{ + for (auto &builtin : builtins) + { + if (name.compare (builtin->as_string ()) == 0) + { + *type = builtin.get (); + return true; + } + } + return false; +} + +void +TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type) +{ + node_id_refs[ref] = id; + resolved[id] = type; + builtins.push_back (std::unique_ptr<TyTy::BaseType> (type)); +} + +void +TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings, + TyTy::BaseType *type) +{ + rust_assert (type != nullptr); + NodeId ref = mappings.get_nodeid (); + HirId id = mappings.get_hirid (); + node_id_refs[ref] = id; + resolved[id] = type; +} + +void +TypeCheckContext::insert_implicit_type (TyTy::BaseType *type) +{ + rust_assert (type != nullptr); + resolved[type->get_ref ()] = type; +} + +void +TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type) +{ + rust_assert (type != nullptr); + resolved[id] = type; +} + +bool +TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const +{ + auto it = resolved.find (id); + if (it == resolved.end ()) + return false; + + *type = it->second; + return true; +} + +void +TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id) +{ + rust_assert (node_id_refs.find (ref) == node_id_refs.end ()); + node_id_refs[ref] = id; +} + +bool +TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id) +{ + auto it = node_id_refs.find (ref); + if (it == node_id_refs.end ()) + return false; + + *id = it->second; + return true; +} + +TyTy::BaseType * +TypeCheckContext::peek_return_type () +{ + rust_assert (!return_type_stack.empty ()); + return return_type_stack.back ().second; +} + +void +TypeCheckContext::push_return_type (TypeCheckContextItem item, + TyTy::BaseType *return_type) +{ + return_type_stack.push_back ({std::move (item), return_type}); +} + +void +TypeCheckContext::pop_return_type () +{ + rust_assert (!return_type_stack.empty ()); + return_type_stack.pop_back (); +} + +TypeCheckContextItem & +TypeCheckContext::peek_context () +{ + rust_assert (!return_type_stack.empty ()); + return return_type_stack.back ().first; +} + +void +TypeCheckContext::iterate (std::function<bool (HirId, TyTy::BaseType *)> cb) +{ + for (auto it = resolved.begin (); it != resolved.end (); it++) + { + if (!cb (it->first, it->second)) + return; + } +} + +bool +TypeCheckContext::have_loop_context () const +{ + return !loop_type_stack.empty (); +} + +void +TypeCheckContext::push_new_loop_context (HirId id, Location locus) +{ + TyTy::BaseType *infer_var + = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL, locus); + loop_type_stack.push_back (infer_var); +} + +void +TypeCheckContext::push_new_while_loop_context (HirId id) +{ + TyTy::BaseType *infer_var = new TyTy::ErrorType (id); + loop_type_stack.push_back (infer_var); +} + +TyTy::BaseType * +TypeCheckContext::peek_loop_context () +{ + return loop_type_stack.back (); +} + +TyTy::BaseType * +TypeCheckContext::pop_loop_context () +{ + auto back = peek_loop_context (); + loop_type_stack.pop_back (); + return back; +} + +void +TypeCheckContext::swap_head_loop_context (TyTy::BaseType *val) +{ + loop_type_stack.pop_back (); + loop_type_stack.push_back (val); +} + +void +TypeCheckContext::insert_trait_reference (DefId id, TraitReference &&ref) +{ + rust_assert (trait_context.find (id) == trait_context.end ()); + trait_context.emplace (id, std::move (ref)); +} + +bool +TypeCheckContext::lookup_trait_reference (DefId id, TraitReference **ref) +{ + auto it = trait_context.find (id); + if (it == trait_context.end ()) + return false; + + *ref = &it->second; + return true; +} + +void +TypeCheckContext::insert_receiver (HirId id, TyTy::BaseType *t) +{ + receiver_context[id] = t; +} + +bool +TypeCheckContext::lookup_receiver (HirId id, TyTy::BaseType **ref) +{ + auto it = receiver_context.find (id); + if (it == receiver_context.end ()) + return false; + + *ref = it->second; + return true; +} + +void +TypeCheckContext::insert_associated_trait_impl ( + HirId id, AssociatedImplTrait &&associated) +{ + rust_assert (associated_impl_traits.find (id) + == associated_impl_traits.end ()); + associated_impl_traits.emplace (id, std::move (associated)); +} + +bool +TypeCheckContext::lookup_associated_trait_impl ( + HirId id, AssociatedImplTrait **associated) +{ + auto it = associated_impl_traits.find (id); + if (it == associated_impl_traits.end ()) + return false; + + *associated = &it->second; + return true; +} + +void +TypeCheckContext::insert_associated_type_mapping (HirId id, HirId mapping) +{ + associated_type_mappings[id] = mapping; +} + +void +TypeCheckContext::clear_associated_type_mapping (HirId id) +{ + auto it = associated_type_mappings.find (id); + if (it != associated_type_mappings.end ()) + associated_type_mappings.erase (it); +} + +// lookup any associated type mappings, the out parameter of mapping is +// allowed to be nullptr which allows this interface to do a simple does exist +// check +bool +TypeCheckContext::lookup_associated_type_mapping (HirId id, HirId *mapping) +{ + auto it = associated_type_mappings.find (id); + if (it == associated_type_mappings.end ()) + return false; + + if (mapping != nullptr) + *mapping = it->second; + + return true; +} + +void +TypeCheckContext::insert_associated_impl_mapping ( + HirId trait_id, const TyTy::BaseType *impl_type, HirId impl_id) +{ + auto it = associated_traits_to_impls.find (trait_id); + if (it == associated_traits_to_impls.end ()) + { + associated_traits_to_impls[trait_id] = {}; + } + + associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id}); +} + +bool +TypeCheckContext::lookup_associated_impl_mapping_for_self ( + HirId trait_id, const TyTy::BaseType *self, HirId *mapping) +{ + auto it = associated_traits_to_impls.find (trait_id); + if (it == associated_traits_to_impls.end ()) + return false; + + for (auto &item : it->second) + { + if (item.first->can_eq (self, false)) + { + *mapping = item.second; + return true; + } + } + return false; +} + +void +TypeCheckContext::insert_autoderef_mappings ( + HirId id, std::vector<Adjustment> &&adjustments) +{ + rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ()); + autoderef_mappings.emplace (id, std::move (adjustments)); +} + +bool +TypeCheckContext::lookup_autoderef_mappings ( + HirId id, std::vector<Adjustment> **adjustments) +{ + auto it = autoderef_mappings.find (id); + if (it == autoderef_mappings.end ()) + return false; + + *adjustments = &it->second; + return true; +} + +void +TypeCheckContext::insert_cast_autoderef_mappings ( + HirId id, std::vector<Adjustment> &&adjustments) +{ + rust_assert (cast_autoderef_mappings.find (id) + == cast_autoderef_mappings.end ()); + cast_autoderef_mappings.emplace (id, std::move (adjustments)); +} + +bool +TypeCheckContext::lookup_cast_autoderef_mappings ( + HirId id, std::vector<Adjustment> **adjustments) +{ + auto it = cast_autoderef_mappings.find (id); + if (it == cast_autoderef_mappings.end ()) + return false; + + *adjustments = &it->second; + return true; +} + +void +TypeCheckContext::insert_variant_definition (HirId id, HirId variant) +{ + auto it = variants.find (id); + rust_assert (it == variants.end ()); + + variants[id] = variant; +} + +bool +TypeCheckContext::lookup_variant_definition (HirId id, HirId *variant) +{ + auto it = variants.find (id); + if (it == variants.end ()) + return false; + + *variant = it->second; + return true; +} + +void +TypeCheckContext::insert_operator_overload (HirId id, TyTy::FnType *call_site) +{ + auto it = operator_overloads.find (id); + rust_assert (it == operator_overloads.end ()); + + operator_overloads[id] = call_site; +} + +bool +TypeCheckContext::lookup_operator_overload (HirId id, TyTy::FnType **call) +{ + auto it = operator_overloads.find (id); + if (it == operator_overloads.end ()) + return false; + + *call = it->second; + return true; +} + +void +TypeCheckContext::insert_unconstrained_check_marker (HirId id, bool status) +{ + unconstrained[id] = status; +} + +bool +TypeCheckContext::have_checked_for_unconstrained (HirId id, bool *result) +{ + auto it = unconstrained.find (id); + bool found = it != unconstrained.end (); + if (!found) + return false; + + *result = it->second; + return true; +} + +void +TypeCheckContext::insert_resolved_predicate (HirId id, + TyTy::TypeBoundPredicate predicate) +{ + auto it = predicates.find (id); + rust_assert (it == predicates.end ()); + + predicates.insert ({id, predicate}); +} + +bool +TypeCheckContext::lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result) +{ + auto it = predicates.find (id); + bool found = it != predicates.end (); + if (!found) + return false; + + *result = it->second; + return true; +} + +void +TypeCheckContext::insert_query (HirId id) +{ + querys_in_progress.insert (id); +} + +void +TypeCheckContext::query_completed (HirId id) +{ + querys_in_progress.erase (id); +} + +bool +TypeCheckContext::query_in_progress (HirId id) const +{ + return querys_in_progress.find (id) != querys_in_progress.end (); +} + +void +TypeCheckContext::insert_trait_query (DefId id) +{ + trait_queries_in_progress.insert (id); +} + +void +TypeCheckContext::trait_query_completed (DefId id) +{ + trait_queries_in_progress.erase (id); +} + +bool +TypeCheckContext::trait_query_in_progress (DefId id) const +{ + return trait_queries_in_progress.find (id) + != trait_queries_in_progress.end (); +} + +// TypeCheckContextItem + +TypeCheckContextItem::Item::Item (HIR::Function *item) : item (item) {} + +TypeCheckContextItem::Item::Item (HIR::ImplBlock *impl_block, + HIR::Function *item) + : impl_item ({impl_block, item}) +{} + +TypeCheckContextItem::Item::Item (HIR::TraitItemFunc *trait_item) + : trait_item (trait_item) +{} + +TypeCheckContextItem::TypeCheckContextItem (HIR::Function *item) + : type (ItemType::ITEM), item (item) +{} + +TypeCheckContextItem::TypeCheckContextItem (HIR::ImplBlock *impl_block, + HIR::Function *item) + : type (ItemType::IMPL_ITEM), item (impl_block, item) +{} + +TypeCheckContextItem::TypeCheckContextItem (HIR::TraitItemFunc *trait_item) + : type (ItemType::TRAIT_ITEM), item (trait_item) +{} + +HIR::Function * +TypeCheckContextItem::get_item () +{ + rust_assert (get_type () == ItemType::ITEM); + return item.item; +} + +std::pair<HIR::ImplBlock *, HIR::Function *> & +TypeCheckContextItem::get_impl_item () +{ + rust_assert (get_type () == ItemType::IMPL_ITEM); + return item.impl_item; +} + +HIR::TraitItemFunc * +TypeCheckContextItem::get_trait_item () +{ + rust_assert (get_type () == ItemType::TRAIT_ITEM); + return item.trait_item; +} + +TypeCheckContextItem::ItemType +TypeCheckContextItem::get_type () const +{ + return type; +} + +TyTy::FnType * +TypeCheckContextItem::get_context_type () +{ + auto &context = *TypeCheckContext::get (); + + HirId reference = UNKNOWN_HIRID; + switch (get_type ()) + { + case ITEM: + reference = get_item ()->get_mappings ().get_hirid (); + break; + + case IMPL_ITEM: + reference = get_impl_item ().second->get_mappings ().get_hirid (); + break; + + case TRAIT_ITEM: + reference = get_trait_item ()->get_mappings ().get_hirid (); + break; + } + + rust_assert (reference != UNKNOWN_HIRID); + + TyTy::BaseType *lookup = nullptr; + bool ok = context.lookup_type (reference, &lookup); + rust_assert (ok); + rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); + return static_cast<TyTy::FnType *> (lookup); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 20a81ad..76d2eef 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -23,6 +23,41 @@ namespace Rust { namespace Resolver { +TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver) + : TypeCheckBase (), receiver (receiver) +{} + +std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> +TypeBoundsProbe::Probe (const TyTy::BaseType *receiver) +{ + TypeBoundsProbe probe (receiver); + probe.scan (); + return probe.trait_references; +} + +bool +TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver, + TraitReference *ref) +{ + for (auto &bound : receiver->get_specified_bounds ()) + { + const TraitReference *b = bound.get (); + if (b->is_equal (*ref)) + return true; + } + + std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds + = Probe (receiver); + for (auto &bound : bounds) + { + const TraitReference *b = bound.first; + if (b->is_equal (*ref)) + return true; + } + + return false; +} + void TypeBoundsProbe::scan () { @@ -57,6 +92,75 @@ TypeBoundsProbe::scan () if (!trait_ref->is_error ()) trait_references.push_back ({trait_ref, path.second}); } + + // marker traits... + assemble_sized_builtin (); +} + +void +TypeBoundsProbe::assemble_sized_builtin () +{ + const TyTy::BaseType *raw = receiver->destructure (); + + // does this thing actually implement sized? + switch (raw->get_kind ()) + { + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + assemble_builtin_candidate (Analysis::RustLangItem::SIZED); + break; + + // not-sure about this.... FIXME + case TyTy::INFER: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + break; + } +} + +void +TypeBoundsProbe::assemble_builtin_candidate ( + Analysis::RustLangItem::ItemType lang_item) +{ + DefId id; + bool found_lang_item = mappings->lookup_lang_item (lang_item, &id); + if (!found_lang_item) + return; + + HIR::Item *item = mappings->lookup_defid (id); + if (item == nullptr) + return; + + rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait); + HIR::Trait *trait = static_cast<HIR::Trait *> (item); + const TyTy::BaseType *raw = receiver->destructure (); + + // assemble the reference + TraitReference *trait_ref = TraitResolver::Resolve (*trait); + trait_references.push_back ({trait_ref, mappings->lookup_builtin_marker ()}); + + rust_debug ("Added builtin lang_item: %s for %s", + Analysis::RustLangItem::ToString (lang_item).c_str (), + raw->get_name ().c_str ()); } TraitReference * @@ -101,7 +205,8 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path) = static_cast<HIR::TypePathSegmentFunction *> (final_seg.get ()); auto &fn = final_function_seg->get_function_path (); - // we need to make implicit generic args which must be an implicit Tuple + // we need to make implicit generic args which must be an implicit + // Tuple auto crate_num = mappings->get_current_crate (); HirId implicit_args_id = mappings->get_next_hir_id (); Analysis::NodeMapping mapping (crate_num, @@ -145,11 +250,10 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path) break; } - // FIXME - // I think this should really be just be if the !args.is_empty() because - // someone might wrongly apply generic arguments where they should not and - // they will be missing error diagnostics - if (predicate.requires_generic_args ()) + // we try to apply generic arguments when they are non empty and or when the + // predicate requires them so that we get the relevant Foo expects x number + // arguments but got zero see test case rust/compile/traits12.rs + if (!args.is_empty () || predicate.requires_generic_args ()) { // this is applying generic arguments to a trait reference predicate.apply_generic_arguments (&args); @@ -222,7 +326,7 @@ TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other) } used_arguments - = SubstitutionArgumentMappings (copied_arg_mappings, + = SubstitutionArgumentMappings (copied_arg_mappings, {}, other.used_arguments.get_locus ()); } @@ -258,7 +362,7 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate &other) } used_arguments - = SubstitutionArgumentMappings (copied_arg_mappings, + = SubstitutionArgumentMappings (copied_arg_mappings, {}, other.used_arguments.get_locus ()); return *this; @@ -331,6 +435,19 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args) if (ok && arg.get_tyty () != nullptr) sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); } + + // associated argument mappings + for (auto &it : subst_mappings.get_binding_args ()) + { + std::string identifier = it.first; + TyTy::BaseType *type = it.second; + + TypeBoundPredicateItem item = lookup_associated_item (identifier); + rust_assert (!item.is_error ()); + + const auto item_ref = item.get_raw_item (); + item_ref->associated_type_set (type); + } } bool @@ -352,6 +469,30 @@ TypeBoundPredicate::lookup_associated_item (const std::string &search) const return TypeBoundPredicateItem (this, trait_item_ref); } +TypeBoundPredicateItem::TypeBoundPredicateItem ( + const TypeBoundPredicate *parent, + const Resolver::TraitItemReference *trait_item_ref) + : parent (parent), trait_item_ref (trait_item_ref) +{} + +TypeBoundPredicateItem +TypeBoundPredicateItem::error () +{ + return TypeBoundPredicateItem (nullptr, nullptr); +} + +bool +TypeBoundPredicateItem::is_error () const +{ + return parent == nullptr || trait_item_ref == nullptr; +} + +const TypeBoundPredicate * +TypeBoundPredicateItem::get_parent () const +{ + return parent; +} + TypeBoundPredicateItem TypeBoundPredicate::lookup_associated_item ( const Resolver::TraitItemReference *ref) const @@ -389,7 +530,8 @@ TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) adjusted_mappings.push_back (std::move (arg)); } - SubstitutionArgumentMappings adjusted (adjusted_mappings, gargs.get_locus (), + SubstitutionArgumentMappings adjusted (adjusted_mappings, {}, + gargs.get_locus (), gargs.get_subst_cb (), true /* trait-mode-flag */); return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted); @@ -407,7 +549,7 @@ TypeBoundPredicate::is_error () const BaseType * TypeBoundPredicate::handle_substitions ( - SubstitutionArgumentMappings subst_mappings) + SubstitutionArgumentMappings &subst_mappings) { for (auto &sub : get_substs ()) { @@ -421,6 +563,19 @@ TypeBoundPredicate::handle_substitions ( p->set_ty_ref (s->get_ty_ref ()); } + // associated argument mappings + for (auto &it : subst_mappings.get_binding_args ()) + { + std::string identifier = it.first; + TyTy::BaseType *type = it.second; + + TypeBoundPredicateItem item = lookup_associated_item (identifier); + rust_assert (!item.is_error ()); + + const auto item_ref = item.get_raw_item (); + item_ref->associated_type_set (type); + } + // FIXME more error handling at some point // used_arguments = subst_mappings; // error_flag |= used_arguments.is_error (); @@ -440,6 +595,13 @@ TypeBoundPredicate::requires_generic_args () const bool TypeBoundPredicate::contains_associated_types () const { + return get_num_associated_bindings () > 0; +} + +size_t +TypeBoundPredicate::get_num_associated_bindings () const +{ + size_t count = 0; auto trait_ref = get (); for (const auto &trait_item : trait_ref->get_trait_items ()) { @@ -447,9 +609,45 @@ TypeBoundPredicate::contains_associated_types () const = trait_item.get_trait_item_type () == Resolver::TraitItemReference::TraitItemType::TYPE; if (is_associated_type) - return true; + count++; } - return false; + return count; +} + +TypeBoundPredicateItem +TypeBoundPredicate::lookup_associated_type (const std::string &search) +{ + TypeBoundPredicateItem item = lookup_associated_item (search); + + // only need to check that it is infact an associated type because other + // wise if it was not found it will just be an error node anyway + if (!item.is_error ()) + { + const auto raw = item.get_raw_item (); + if (raw->get_trait_item_type () + != Resolver::TraitItemReference::TraitItemType::TYPE) + return TypeBoundPredicateItem::error (); + } + return item; +} + +std::vector<TypeBoundPredicateItem> +TypeBoundPredicate::get_associated_type_items () +{ + std::vector<TypeBoundPredicateItem> items; + auto trait_ref = get (); + for (const auto &trait_item : trait_ref->get_trait_items ()) + { + bool is_associated_type + = trait_item.get_trait_item_type () + == Resolver::TraitItemReference::TraitItemType::TYPE; + if (is_associated_type) + { + TypeBoundPredicateItem item (this, &trait_item); + items.push_back (std::move (item)); + } + } + return items; } // trait item reference diff --git a/gcc/rust/typecheck/rust-tyty-bounds.h b/gcc/rust/typecheck/rust-tyty-bounds.h new file mode 100644 index 0000000..6240480 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-bounds.h @@ -0,0 +1,88 @@ +// Copyright (C) 2020-2023 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_BOUNDS_H +#define RUST_TYTY_BOUNDS_H + +#include "rust-location.h" + +namespace Rust { + +namespace Resolver { +class TraitReference; +class TraitItemReference; +class AssociatedImplTrait; +} // namespace Resolver + +namespace TyTy { + +class BaseType; +class TypeBoundPredicate; +class TypeBoundPredicateItem +{ +public: + TypeBoundPredicateItem (const TypeBoundPredicate *parent, + const Resolver::TraitItemReference *trait_item_ref); + + static TypeBoundPredicateItem error (); + + bool is_error () const; + + BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); + + const Resolver::TraitItemReference *get_raw_item () const; + + bool needs_implementation () const; + + const TypeBoundPredicate *get_parent () const; + + Location get_locus () const; + +private: + const TypeBoundPredicate *parent; + const Resolver::TraitItemReference *trait_item_ref; +}; + +class TypeBoundsMappings +{ +protected: + TypeBoundsMappings (std::vector<TypeBoundPredicate> specified_bounds); + +public: + std::vector<TypeBoundPredicate> &get_specified_bounds (); + + const std::vector<TypeBoundPredicate> &get_specified_bounds () const; + + size_t num_specified_bounds () const; + + std::string raw_bounds_as_string () const; + + std::string bounds_as_string () const; + + std::string raw_bounds_as_name () const; + +protected: + void add_bound (TypeBoundPredicate predicate); + + std::vector<TypeBoundPredicate> specified_bounds; +}; + +} // namespace TyTy +} // namespace Rust + +#endif // RUST_TYTY_BOUNDS_H diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc index d520b59..f0846ae 100644 --- a/gcc/rust/typecheck/rust-tyty-call.cc +++ b/gcc/rust/typecheck/rust-tyty-call.cc @@ -85,7 +85,6 @@ TypeCheckCallExpr::visit (ADTType &type) void TypeCheckCallExpr::visit (FnType &type) { - type.monomorphize (); if (call.num_params () != type.num_params ()) { if (type.is_varadic ()) @@ -123,7 +122,7 @@ TypeCheckCallExpr::visit (FnType &type) return; } - // it might be a varadic function + // it might be a variadic function if (i < type.num_params ()) { auto fnparam = type.param_at (i); @@ -141,11 +140,63 @@ TypeCheckCallExpr::visit (FnType &type) argument->get_locus ()); if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (argument->get_locus (), - "Type Resolution failure on parameter"); return; } } + else + { + switch (argument_expr_tyty->get_kind ()) + { + case TyTy::TypeKind::ERROR: + return; + case TyTy::TypeKind::INT: { + auto &int_ty + = static_cast<TyTy::IntType &> (*argument_expr_tyty); + if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8) + || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16)) + { + rust_error_at (arg_locus, + "expected %<c_int%> variadic argument"); + return; + } + break; + } + case TyTy::TypeKind::UINT: { + auto &uint_ty + = static_cast<TyTy::UintType &> (*argument_expr_tyty); + if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8) + || (uint_ty.get_uint_kind () + == TyTy::UintType::UintKind::U16)) + { + rust_error_at (arg_locus, + "expected %<c_uint%> variadic argument"); + return; + } + break; + } + case TyTy::TypeKind::FLOAT: { + if (static_cast<TyTy::FloatType &> (*argument_expr_tyty) + .get_float_kind () + == TyTy::FloatType::FloatKind::F32) + { + rust_error_at (arg_locus, + "expected %<c_double%> variadic argument"); + return; + } + break; + } + case TyTy::TypeKind::BOOL: + rust_error_at (arg_locus, "expected %<c_int%> variadic argument"); + return; + case TyTy::TypeKind::FNDEF: + rust_error_at (arg_locus, + "unexpected function definition type as variadic " + "argument - cast to function pointer"); + return; + default: + break; + } + } i++; } @@ -194,8 +245,6 @@ TypeCheckCallExpr::visit (FnPtr &type) TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ()); if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (argument->get_locus (), - "Type Resolution failure on parameter"); return; } @@ -302,7 +351,6 @@ TypeCheckMethodCallExpr::check (FnType &type) TyWithLocation (argument_expr_tyty, arg_locus), arg_locus); if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (arg_locus, "Type Resolution failure on parameter"); return new ErrorType (type.get_ref ()); } diff --git a/gcc/rust/typecheck/rust-tyty-rules.h b/gcc/rust/typecheck/rust-tyty-rules.h deleted file mode 100644 index cfe2692..0000000 --- a/gcc/rust/typecheck/rust-tyty-rules.h +++ /dev/null @@ -1,1406 +0,0 @@ -// Copyright (C) 2020-2023 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_RULES -#define RUST_TYTY_RULES - -#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 { - -/* Rules specify how to unify two Ty. For example, the result of unifying the - two tuples (u64, A) and (B, i64) would be (u64, i64). - - Performing a unification requires a double dispatch. To illustrate, suppose - we want to unify `ty1` and `ty2`. Here's what it looks like: - 1. The caller calls `ty1.unify(ty2)`. This is the first dispatch. - 2. `ty1` creates a rule specific to its type(e.g. TupleRules). - 3. The rule calls `ty2.accept_vis(rule)`. This is the second dispatch. - 4. `ty2` calls `rule.visit(*this)`, which will method-overload to the - correct implementation at compile time. - - The nice thing about Rules is that they seperate unification logic from the - representation of Ty. To support unifying a new Ty, implement its - `accept_vis` and `unify` method to pass the unification request to Rules. - Then, create a new `XXXRules` class and implement one `visit` method for - every Ty it can unify with. */ -class BaseRules : public TyVisitor -{ -public: - virtual ~BaseRules () {} - - /* Unify two ty. Returns a pointer to the newly-created unified ty, or nullptr - if the two types cannot be unified. The caller is responsible for releasing - the memory of the returned ty. - - This method is meant to be used internally by Ty. If you're trying to unify - two ty, you can simply call `unify` on ty themselves. */ - virtual BaseType *unify (BaseType *other) - { - if (other->get_kind () == TypeKind::PARAM) - { - ParamType *p = static_cast<ParamType *> (other); - other = p->resolve (); - } - else if (other->get_kind () == TypeKind::PLACEHOLDER) - { - PlaceholderType *p = static_cast<PlaceholderType *> (other); - if (p->can_resolve ()) - { - other = p->resolve (); - return get_base ()->unify (other); - } - } - else if (other->get_kind () == TypeKind::PROJECTION) - { - ProjectionType *p = static_cast<ProjectionType *> (other); - other = p->get (); - return get_base ()->unify (other); - } - - other->accept_vis (*this); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - return resolved; - - resolved->append_reference (get_base ()->get_ref ()); - resolved->append_reference (other->get_ref ()); - for (auto ref : get_base ()->get_combined_refs ()) - resolved->append_reference (ref); - for (auto ref : other->get_combined_refs ()) - resolved->append_reference (ref); - - other->append_reference (resolved->get_ref ()); - other->append_reference (get_base ()->get_ref ()); - get_base ()->append_reference (resolved->get_ref ()); - get_base ()->append_reference (other->get_ref ()); - - bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER; - bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER; - bool results_is_non_general_infer_var - = (result_is_infer_var - && (static_cast<InferType *> (resolved))->get_infer_kind () - != TyTy::InferType::GENERAL); - if (result_resolved || results_is_non_general_infer_var) - { - for (auto &ref : resolved->get_combined_refs ()) - { - TyTy::BaseType *ref_tyty = nullptr; - bool ok = context->lookup_type (ref, &ref_tyty); - if (!ok) - continue; - - // if any of the types are inference variables lets fix them - if (ref_tyty->get_kind () == TyTy::TypeKind::INFER) - { - context->insert_type ( - Analysis::NodeMapping (mappings->get_current_crate (), - UNKNOWN_NODEID, ref, - UNKNOWN_LOCAL_DEFID), - resolved->clone ()); - } - } - } - return resolved; - } - - virtual void visit (TupleType &) override {} - - virtual void visit (ADTType &) override {} - - virtual void visit (InferType &) override {} - - virtual void visit (FnType &) override {} - - virtual void visit (FnPtr &) override {} - - virtual void visit (ArrayType &) override {} - - virtual void visit (SliceType &) override {} - - virtual void visit (BoolType &) override {} - - virtual void visit (IntType &) override {} - - virtual void visit (UintType &) override {} - - virtual void visit (USizeType &) override {} - - virtual void visit (ISizeType &) override {} - - virtual void visit (FloatType &) override {} - - virtual void visit (ErrorType &) override {} - - virtual void visit (CharType &) override {} - - virtual void visit (ReferenceType &) override {} - - virtual void visit (PointerType &) override {} - - virtual void visit (ParamType &) override {} - - virtual void visit (StrType &) override {} - - virtual void visit (NeverType &) override {} - - virtual void visit (PlaceholderType &) override {} - - virtual void visit (ProjectionType &) override {} - - virtual void visit (DynamicObjectType &) override {} - - virtual void visit (ClosureType &) override {} - -protected: - BaseRules (BaseType *base) - : mappings (Analysis::Mappings::get ()), - context (Resolver::TypeCheckContext::get ()), - resolved (new ErrorType (base->get_ref (), base->get_ref ())) - {} - - Analysis::Mappings *mappings; - Resolver::TypeCheckContext *context; - - /* Temporary storage for the result of a unification. - We could return the result directly instead of storing it in the rule - object, but that involves modifying the visitor pattern to accommodate - the return value, which is too complex. */ - BaseType *resolved; - -private: - /* Returns a pointer to the ty that created this rule. */ - virtual BaseType *get_base () = 0; -}; - -class InferRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - InferRules (InferType *base) : BaseRules (base), base (base) {} - - void visit (BoolType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::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) - { - resolved = type.clone (); - return; - } - - BaseRules::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) - { - resolved = type.clone (); - return; - } - - BaseRules::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) - { - resolved = type.clone (); - return; - } - - BaseRules::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) - { - resolved = type.clone (); - return; - } - - BaseRules::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) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ArrayType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (SliceType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ADTType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (TupleType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (InferType &type) override - { - switch (base->get_infer_kind ()) - { - case InferType::InferTypeKind::GENERAL: - resolved = type.clone (); - return; - - case InferType::InferTypeKind::INTEGRAL: { - if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) - { - resolved = type.clone (); - return; - } - else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) - { - resolved = base->clone (); - return; - } - } - break; - - case InferType::InferTypeKind::FLOAT: { - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - resolved = type.clone (); - return; - } - else if (type.get_infer_kind () == InferType::InferTypeKind::GENERAL) - { - resolved = base->clone (); - return; - } - } - break; - } - - BaseRules::visit (type); - } - - void visit (CharType &type) override - { - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - } - - void visit (ReferenceType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (PointerType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ParamType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (DynamicObjectType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - - void visit (ClosureType &type) override - { - bool is_valid - = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); - if (is_valid) - { - resolved = type.clone (); - return; - } - - BaseRules::visit (type); - } - -private: - BaseType *get_base () override { return base; } - - InferType *base; -}; - -class FnRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FnRules (FnType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FnType &type) override - { - if (base->num_params () != type.num_params ()) - { - BaseRules::visit (type); - return; - } - - 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) - { - BaseRules::visit (type); - return; - } - } - - auto unified_return - = base->get_return_type ()->unify (type.get_return_type ()); - if (unified_return == nullptr) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - FnType *base; -}; - -class FnptrRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FnptrRules (FnPtr *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (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) - { - BaseRules::visit (type); - return; - } - - if (base->num_params () != type.num_params ()) - { - BaseRules::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) - { - BaseRules::visit (type); - return; - } - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - 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) - { - BaseRules::visit (type); - return; - } - - if (base->num_params () != type.num_params ()) - { - BaseRules::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) - { - BaseRules::visit (type); - return; - } - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - FnPtr *base; -}; - -class ClosureRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ClosureRules (ClosureType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (ClosureType &type) override - { - if (base->get_def_id () != type.get_def_id ()) - { - BaseRules::visit (type); - return; - } - - TyTy::BaseType *args_res - = base->get_parameters ().unify (&type.get_parameters ()); - if (args_res == nullptr || args_res->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - TyTy::BaseType *res - = base->get_result_type ().unify (&type.get_result_type ()); - if (res == nullptr || res->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ClosureType *base; -}; - -class ArrayRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ArrayRules (ArrayType *base) : BaseRules (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) - { - BaseRules::visit (type); - return; - } - - resolved - = new ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, type.get_capacity_expr (), - TyVar (base_resolved->get_ref ())); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ArrayType *base; -}; - -class SliceRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - SliceRules (SliceType *base) : BaseRules (base), base (base) {} - - void visit (SliceType &type) override - { - // check base type - auto base_resolved - = base->get_element_type ()->unify (type.get_element_type ()); - if (base_resolved == nullptr) - { - BaseRules::visit (type); - return; - } - - resolved = new SliceType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - TyVar (base_resolved->get_ref ())); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - SliceType *base; -}; - -class BoolRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - BoolRules (BoolType *base) : BaseRules (base), base (base) {} - - void visit (BoolType &type) override - { - resolved = new BoolType (type.get_ref (), type.get_ty_ref ()); - } - - void visit (InferType &type) override - { - switch (type.get_infer_kind ()) - { - case InferType::InferTypeKind::GENERAL: - resolved = base->clone (); - break; - - default: - BaseRules::visit (type); - break; - } - } - -private: - BaseType *get_base () override { return base; } - - BoolType *base; -}; - -class IntRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - IntRules (IntType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (IntType &type) override - { - if (type.get_int_kind () != base->get_int_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved - = new IntType (type.get_ref (), type.get_ty_ref (), type.get_int_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - IntType *base; -}; - -class UintRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - UintRules (UintType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (UintType &type) override - { - if (type.get_uint_kind () != base->get_uint_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved = new UintType (type.get_ref (), type.get_ty_ref (), - type.get_uint_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - UintType *base; -}; - -class FloatRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - FloatRules (FloatType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (FloatType &type) override - { - if (type.get_float_kind () != base->get_float_kind ()) - { - BaseRules::visit (type); - return; - } - - resolved = new FloatType (type.get_ref (), type.get_ty_ref (), - type.get_float_kind ()); - } - -private: - BaseType *get_base () override { return base; } - - FloatType *base; -}; - -class ADTRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ADTRules (ADTType *base) : BaseRules (base), base (base) {} - - void visit (ADTType &type) override - { - if (base->get_adt_kind () != type.get_adt_kind ()) - { - BaseRules::visit (type); - return; - } - - if (base->get_identifier ().compare (type.get_identifier ()) != 0) - { - BaseRules::visit (type); - return; - } - - if (base->number_of_variants () != type.number_of_variants ()) - { - BaseRules::visit (type); - return; - } - - for (size_t i = 0; i < type.number_of_variants (); ++i) - { - TyTy::VariantDef *a = base->get_variants ().at (i); - TyTy::VariantDef *b = type.get_variants ().at (i); - - if (a->num_fields () != b->num_fields ()) - { - BaseRules::visit (type); - return; - } - - for (size_t j = 0; j < a->num_fields (); j++) - { - TyTy::StructFieldType *base_field = a->get_field_at_index (j); - TyTy::StructFieldType *other_field = b->get_field_at_index (j); - - TyTy::BaseType *this_field_ty = base_field->get_field_type (); - TyTy::BaseType *other_field_ty = other_field->get_field_type (); - - BaseType *unified_ty = this_field_ty->unify (other_field_ty); - if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) - return; - } - } - - // generic args for the unit-struct case - if (type.is_unit () && base->is_unit ()) - { - rust_assert (type.get_num_substitutions () - == base->get_num_substitutions ()); - - for (size_t i = 0; i < type.get_num_substitutions (); i++) - { - auto &a = base->get_substs ().at (i); - auto &b = type.get_substs ().at (i); - - auto pa = a.get_param_ty (); - auto pb = b.get_param_ty (); - - auto res = pa->unify (pb); - if (res->get_kind () == TyTy::TypeKind::ERROR) - { - return; - } - } - } - - resolved = type.clone (); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ADTType *base; -}; - -class TupleRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - TupleRules (TupleType *base) : BaseRules (base), base (base) {} - - void visit (TupleType &type) override - { - if (base->num_fields () != type.num_fields ()) - { - BaseRules::visit (type); - return; - } - - std::vector<TyVar> fields; - for (size_t i = 0; i < base->num_fields (); i++) - { - BaseType *bo = base->get_field (i); - BaseType *fo = type.get_field (i); - - BaseType *unified_ty = bo->unify (fo); - if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) - return; - - fields.push_back (TyVar (unified_ty->get_ref ())); - } - - resolved = new TyTy::TupleType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, fields); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - TupleType *base; -}; - -class USizeRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - USizeRules (USizeType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (USizeType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - USizeType *base; -}; - -class ISizeRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ISizeRules (ISizeType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - // cant assign a float inference variable - if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (ISizeType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - ISizeType *base; -}; - -class CharRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - CharRules (CharType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - - void visit (CharType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - CharType *base; -}; - -class ReferenceRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ReferenceRules (ReferenceType *base) : BaseRules (base), base (base) {} - - void visit (ReferenceType &type) override - { - auto base_type = base->get_base (); - auto other_base_type = type.get_base (); - - TyTy::BaseType *base_resolved = base_type->unify (other_base_type); - if (base_resolved == nullptr - || base_resolved->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - // rust is permissive about mutablity here you can always go from mutable to - // immutable but not the otherway round - bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (!mutability_ok) - { - BaseRules::visit (type); - return; - } - - resolved = new ReferenceType (base->get_ref (), base->get_ty_ref (), - TyVar (base_resolved->get_ref ()), - base->mutability ()); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - ReferenceType *base; -}; - -class PointerRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - PointerRules (PointerType *base) : BaseRules (base), base (base) {} - - void visit (PointerType &type) override - { - auto base_type = base->get_base (); - auto other_base_type = type.get_base (); - - TyTy::BaseType *base_resolved = base_type->unify (other_base_type); - if (base_resolved == nullptr - || base_resolved->get_kind () == TypeKind::ERROR) - { - BaseRules::visit (type); - return; - } - - // rust is permissive about mutablity here you can always go from mutable to - // immutable but not the otherway round - bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (!mutability_ok) - { - BaseRules::visit (type); - return; - } - - resolved = new PointerType (base->get_ref (), base->get_ty_ref (), - TyVar (base_resolved->get_ref ()), - base->mutability ()); - } - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - resolved->set_ref (type.get_ref ()); - } - -private: - BaseType *get_base () override { return base; } - - PointerType *base; -}; - -class ParamRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - ParamRules (ParamType *base) : BaseRules (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 - BaseType *unify (BaseType *other) override final - { - if (!base->can_resolve ()) - return BaseRules::unify (other); - - auto lookup = base->resolve (); - return lookup->unify (other); - } - - void visit (ParamType &type) override - { - if (base->get_symbol ().compare (type.get_symbol ()) != 0) - { - BaseRules::visit (type); - return; - } - - 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; } - - ParamType *base; -}; - -class StrRules : public BaseRules -{ - // FIXME we will need a enum for the StrType like ByteBuf etc.. - using Rust::TyTy::BaseRules::visit; - -public: - StrRules (StrType *base) : BaseRules (base), base (base) {} - - void visit (StrType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - StrType *base; -}; - -class NeverRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - NeverRules (NeverType *base) : BaseRules (base), base (base) {} - - void visit (NeverType &type) override { resolved = type.clone (); } - -private: - BaseType *get_base () override { return base; } - - NeverType *base; -}; - -class PlaceholderRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - PlaceholderRules (PlaceholderType *base) : BaseRules (base), base (base) {} - - BaseType *unify (BaseType *other) override final - { - if (!base->can_resolve ()) - return BaseRules::unify (other); - - BaseType *lookup = base->resolve (); - return lookup->unify (other); - } - - void visit (PlaceholderType &type) override - { - if (base->get_symbol ().compare (type.get_symbol ()) != 0) - { - BaseRules::visit (type); - return; - } - - 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; } - - PlaceholderType *base; -}; - -class DynamicRules : public BaseRules -{ - using Rust::TyTy::BaseRules::visit; - -public: - DynamicRules (DynamicObjectType *base) : BaseRules (base), base (base) {} - - void visit (InferType &type) override - { - if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - - void visit (DynamicObjectType &type) override - { - if (base->num_specified_bounds () != type.num_specified_bounds ()) - { - BaseRules::visit (type); - return; - } - - Location ref_locus = mappings->lookup_location (type.get_ref ()); - if (!base->bounds_compatible (type, ref_locus, true)) - { - BaseRules::visit (type); - return; - } - - resolved = base->clone (); - } - -private: - BaseType *get_base () override { return base; } - - DynamicObjectType *base; -}; - -} // namespace TyTy -} // namespace Rust - -#endif // RUST_TYTY_RULES diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc new file mode 100644 index 0000000..d2f6cf6 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -0,0 +1,1048 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-tyty-subst.h" +#include "rust-hir-full.h" +#include "rust-tyty.h" +#include "rust-hir-type-check.h" +#include "rust-substitution-mapper.h" +#include "rust-hir-type-check-type.h" + +namespace Rust { +namespace TyTy { + +SubstitutionParamMapping::SubstitutionParamMapping ( + const HIR::TypeParam &generic, ParamType *param) + : generic (generic), param (param) +{} + +SubstitutionParamMapping::SubstitutionParamMapping ( + const SubstitutionParamMapping &other) + : generic (other.generic), param (other.param) +{} + +std::string +SubstitutionParamMapping::as_string () const +{ + if (param == nullptr) + return "nullptr"; + + return param->get_name (); +} + +SubstitutionParamMapping +SubstitutionParamMapping::clone () const +{ + return SubstitutionParamMapping (generic, + static_cast<ParamType *> (param->clone ())); +} + +ParamType * +SubstitutionParamMapping::get_param_ty () +{ + return param; +} + +const ParamType * +SubstitutionParamMapping::get_param_ty () const +{ + return param; +} + +const HIR::TypeParam & +SubstitutionParamMapping::get_generic_param () const +{ + return generic; +} + +bool +SubstitutionParamMapping::needs_substitution () const +{ + return !(get_param_ty ()->is_concrete ()); +} + +Location +SubstitutionParamMapping::get_param_locus () const +{ + return generic.get_locus (); +} + +bool +SubstitutionParamMapping::param_has_default_ty () const +{ + return generic.has_type (); +} + +BaseType * +SubstitutionParamMapping::get_default_ty () const +{ + TyVar var (generic.get_type_mappings ().get_hirid ()); + return var.get_tyty (); +} + +bool +SubstitutionParamMapping::need_substitution () const +{ + if (!param->can_resolve ()) + return true; + + auto resolved = param->resolve (); + return !resolved->is_concrete (); +} + +bool +SubstitutionParamMapping::fill_param_ty ( + SubstitutionArgumentMappings &subst_mappings, Location locus) +{ + SubstitutionArg arg = SubstitutionArg::error (); + bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg); + if (!ok) + return true; + + TyTy::BaseType &type = *arg.get_tyty (); + if (type.get_kind () == TyTy::TypeKind::INFER) + { + type.inherit_bounds (*param); + } + + if (type.get_kind () == TypeKind::PARAM) + { + // delete param; + param = static_cast<ParamType *> (type.clone ()); + } + else + { + // check the substitution is compatible with bounds + rust_debug_loc (locus, + "fill_param_ty bounds_compatible: param %s type %s", + param->get_name ().c_str (), type.get_name ().c_str ()); + + if (!param->is_implicit_self_trait ()) + { + if (!param->bounds_compatible (type, locus, true)) + return false; + } + + // recursively pass this down to all HRTB's + for (auto &bound : param->get_specified_bounds ()) + bound.handle_substitions (subst_mappings); + + param->set_ty_ref (type.get_ref ()); + subst_mappings.on_param_subst (*param, arg); + } + + return true; +} + +void +SubstitutionParamMapping::override_context () +{ + if (!param->can_resolve ()) + return; + + auto mappings = Analysis::Mappings::get (); + auto context = Resolver::TypeCheckContext::get (); + + context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), + UNKNOWN_NODEID, + param->get_ref (), + UNKNOWN_LOCAL_DEFID), + param->resolve ()); +} + +SubstitutionArg::SubstitutionArg (const SubstitutionParamMapping *param, + BaseType *argument) + : param (param), argument (argument) +{} + +SubstitutionArg::SubstitutionArg (const SubstitutionArg &other) + : param (other.param), argument (other.argument) +{} + +SubstitutionArg & +SubstitutionArg::operator= (const SubstitutionArg &other) +{ + param = other.param; + argument = other.argument; + return *this; +} + +BaseType * +SubstitutionArg::get_tyty () +{ + return argument; +} + +const BaseType * +SubstitutionArg::get_tyty () const +{ + return argument; +} + +const SubstitutionParamMapping * +SubstitutionArg::get_param_mapping () const +{ + return param; +} + +SubstitutionArg +SubstitutionArg::error () +{ + return SubstitutionArg (nullptr, nullptr); +} + +bool +SubstitutionArg::is_error () const +{ + return param == nullptr || argument == nullptr; +} + +bool +SubstitutionArg::is_conrete () const +{ + if (argument == nullptr) + return false; + + if (argument->get_kind () == TyTy::TypeKind::PARAM) + return false; + + return argument->is_concrete (); +} + +std::string +SubstitutionArg::as_string () const +{ + return param->as_string () + + (argument != nullptr ? ":" + argument->as_string () : ""); +} + +// SubstitutionArgumentMappings + +SubstitutionArgumentMappings::SubstitutionArgumentMappings ( + std::vector<SubstitutionArg> mappings, + std::map<std::string, BaseType *> binding_args, Location locus, + ParamSubstCb param_subst_cb, bool trait_item_flag) + : mappings (mappings), binding_args (binding_args), locus (locus), + param_subst_cb (param_subst_cb), trait_item_flag (trait_item_flag) +{} + +SubstitutionArgumentMappings::SubstitutionArgumentMappings ( + const SubstitutionArgumentMappings &other) + : mappings (other.mappings), binding_args (other.binding_args), + locus (other.locus), param_subst_cb (nullptr), + trait_item_flag (other.trait_item_flag) +{} + +SubstitutionArgumentMappings & +SubstitutionArgumentMappings::operator= ( + const SubstitutionArgumentMappings &other) +{ + mappings = other.mappings; + binding_args = other.binding_args; + locus = other.locus; + param_subst_cb = nullptr; + trait_item_flag = other.trait_item_flag; + + return *this; +} + +SubstitutionArgumentMappings +SubstitutionArgumentMappings::error () +{ + return SubstitutionArgumentMappings ({}, {}, Location (), nullptr, false); +} + +bool +SubstitutionArgumentMappings::is_error () const +{ + return mappings.size () == 0; +} + +bool +SubstitutionArgumentMappings::get_argument_for_symbol ( + const ParamType *param_to_find, SubstitutionArg *argument) +{ + for (auto &mapping : mappings) + { + const SubstitutionParamMapping *param = mapping.get_param_mapping (); + const ParamType *p = param->get_param_ty (); + + if (p->get_symbol ().compare (param_to_find->get_symbol ()) == 0) + { + *argument = mapping; + return true; + } + } + return false; +} + +bool +SubstitutionArgumentMappings::get_argument_at (size_t index, + SubstitutionArg *argument) +{ + if (index > mappings.size ()) + return false; + + *argument = mappings.at (index); + return true; +} + +bool +SubstitutionArgumentMappings::is_concrete () const +{ + for (auto &mapping : mappings) + { + if (!mapping.is_conrete ()) + return false; + } + return true; +} + +Location +SubstitutionArgumentMappings::get_locus () const +{ + return locus; +} + +size_t +SubstitutionArgumentMappings::size () const +{ + return mappings.size (); +} + +bool +SubstitutionArgumentMappings::is_empty () const +{ + return size () == 0; +} + +std::vector<SubstitutionArg> & +SubstitutionArgumentMappings::get_mappings () +{ + return mappings; +} + +const std::vector<SubstitutionArg> & +SubstitutionArgumentMappings::get_mappings () const +{ + return mappings; +} + +std::map<std::string, BaseType *> & +SubstitutionArgumentMappings::get_binding_args () +{ + return binding_args; +} + +const std::map<std::string, BaseType *> & +SubstitutionArgumentMappings::get_binding_args () const +{ + return binding_args; +} + +std::string +SubstitutionArgumentMappings::as_string () const +{ + std::string buffer; + for (auto &mapping : mappings) + { + buffer += mapping.as_string () + ", "; + } + return "<" + buffer + ">"; +} + +void +SubstitutionArgumentMappings::on_param_subst (const ParamType &p, + const SubstitutionArg &a) const +{ + if (param_subst_cb == nullptr) + return; + + param_subst_cb (p, a); +} + +ParamSubstCb +SubstitutionArgumentMappings::get_subst_cb () const +{ + return param_subst_cb; +} + +bool +SubstitutionArgumentMappings::trait_item_mode () const +{ + return trait_item_flag; +} + +// SubstitutionRef + +SubstitutionRef::SubstitutionRef ( + std::vector<SubstitutionParamMapping> substitutions, + SubstitutionArgumentMappings arguments) + : substitutions (substitutions), used_arguments (arguments) +{} + +bool +SubstitutionRef::has_substitutions () const +{ + return substitutions.size () > 0; +} + +std::string +SubstitutionRef::subst_as_string () const +{ + std::string buffer; + for (size_t i = 0; i < substitutions.size (); i++) + { + const SubstitutionParamMapping &sub = substitutions.at (i); + buffer += sub.as_string (); + + if ((i + 1) < substitutions.size ()) + buffer += ", "; + } + + return buffer.empty () ? "" : "<" + buffer + ">"; +} + +bool +SubstitutionRef::supports_associated_bindings () const +{ + return get_num_associated_bindings () > 0; +} + +size_t +SubstitutionRef::get_num_associated_bindings () const +{ + return 0; +} + +TypeBoundPredicateItem +SubstitutionRef::lookup_associated_type (const std::string &search) +{ + return TypeBoundPredicateItem::error (); +} + +size_t +SubstitutionRef::get_num_substitutions () const +{ + return substitutions.size (); +} + +std::vector<SubstitutionParamMapping> & +SubstitutionRef::get_substs () +{ + return substitutions; +} + +const std::vector<SubstitutionParamMapping> & +SubstitutionRef::get_substs () const +{ + return substitutions; +} + +std::vector<SubstitutionParamMapping> +SubstitutionRef::clone_substs () const +{ + std::vector<SubstitutionParamMapping> clone; + + for (auto &sub : substitutions) + clone.push_back (sub.clone ()); + + return clone; +} + +void +SubstitutionRef::override_context () +{ + for (auto &sub : substitutions) + { + sub.override_context (); + } +} + +bool +SubstitutionRef::needs_substitution () const +{ + for (auto &sub : substitutions) + { + if (sub.need_substitution ()) + return true; + } + return false; +} + +bool +SubstitutionRef::was_substituted () const +{ + return !needs_substitution (); +} + +SubstitutionArgumentMappings & +SubstitutionRef::get_substitution_arguments () +{ + return used_arguments; +} + +const SubstitutionArgumentMappings & +SubstitutionRef::get_substitution_arguments () const +{ + return used_arguments; +} + +size_t +SubstitutionRef::num_required_substitutions () const +{ + size_t n = 0; + for (auto &p : substitutions) + { + if (p.needs_substitution ()) + n++; + } + return n; +} + +size_t +SubstitutionRef::min_required_substitutions () const +{ + size_t n = 0; + for (auto &p : substitutions) + { + if (p.needs_substitution () && !p.param_has_default_ty ()) + n++; + } + return n; +} + +SubstitutionArgumentMappings +SubstitutionRef::get_used_arguments () const +{ + return used_arguments; +} + +SubstitutionArgumentMappings +SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args) +{ + std::map<std::string, BaseType *> binding_arguments; + if (args.get_binding_args ().size () > 0) + { + if (supports_associated_bindings ()) + { + if (args.get_binding_args ().size () > get_num_associated_bindings ()) + { + RichLocation r (args.get_locus ()); + + rust_error_at (r, + "generic item takes at most %lu type binding " + "arguments but %lu were supplied", + (unsigned long) get_num_associated_bindings (), + (unsigned long) args.get_binding_args ().size ()); + return SubstitutionArgumentMappings::error (); + } + + for (auto &binding : args.get_binding_args ()) + { + BaseType *resolved + = Resolver::TypeCheckType::Resolve (binding.get_type ().get ()); + if (resolved == nullptr + || resolved->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (binding.get_locus (), + "failed to resolve type arguments"); + return SubstitutionArgumentMappings::error (); + } + + // resolve to relevant binding + auto binding_item + = lookup_associated_type (binding.get_identifier ()); + if (binding_item.is_error ()) + { + rust_error_at (binding.get_locus (), + "unknown associated type binding: %s", + binding.get_identifier ().c_str ()); + return SubstitutionArgumentMappings::error (); + } + + binding_arguments[binding.get_identifier ()] = resolved; + } + } + else + { + RichLocation r (args.get_locus ()); + for (auto &binding : args.get_binding_args ()) + r.add_range (binding.get_locus ()); + + rust_error_at (r, "associated type bindings are not allowed here"); + return SubstitutionArgumentMappings::error (); + } + } + + // for inherited arguments + size_t offs = used_arguments.size (); + if (args.get_type_args ().size () + offs > substitutions.size ()) + { + RichLocation r (args.get_locus ()); + r.add_range (substitutions.front ().get_param_locus ()); + + rust_error_at ( + r, + "generic item takes at most %lu type arguments but %lu were supplied", + (unsigned long) substitutions.size (), + (unsigned long) args.get_type_args ().size ()); + return SubstitutionArgumentMappings::error (); + } + + if (args.get_type_args ().size () + offs < min_required_substitutions ()) + { + RichLocation r (args.get_locus ()); + r.add_range (substitutions.front ().get_param_locus ()); + + rust_error_at ( + r, + "generic item takes at least %lu type arguments but %lu were supplied", + (unsigned long) (min_required_substitutions () - offs), + (unsigned long) args.get_type_args ().size ()); + return SubstitutionArgumentMappings::error (); + } + + std::vector<SubstitutionArg> mappings = used_arguments.get_mappings (); + for (auto &arg : args.get_type_args ()) + { + BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ()); + if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (args.get_locus (), "failed to resolve type arguments"); + return SubstitutionArgumentMappings::error (); + } + + SubstitutionArg subst_arg (&substitutions.at (offs), resolved); + offs++; + mappings.push_back (std::move (subst_arg)); + } + + // we must need to fill out defaults + size_t left_over + = num_required_substitutions () - min_required_substitutions (); + if (left_over > 0) + { + for (size_t offs = mappings.size (); offs < substitutions.size (); offs++) + { + SubstitutionParamMapping ¶m = substitutions.at (offs); + rust_assert (param.param_has_default_ty ()); + + BaseType *resolved = param.get_default_ty (); + if (resolved->get_kind () == TypeKind::ERROR) + return SubstitutionArgumentMappings::error (); + + // this resolved default might already contain default parameters + if (resolved->contains_type_parameters ()) + { + SubstitutionArgumentMappings intermediate (mappings, + binding_arguments, + args.get_locus ()); + resolved = Resolver::SubstMapperInternal::Resolve (resolved, + intermediate); + + if (resolved->get_kind () == TypeKind::ERROR) + return SubstitutionArgumentMappings::error (); + } + + SubstitutionArg subst_arg (¶m, resolved); + mappings.push_back (std::move (subst_arg)); + } + } + + return SubstitutionArgumentMappings (mappings, binding_arguments, + args.get_locus ()); +} + +BaseType * +SubstitutionRef::infer_substitions (Location locus) +{ + std::vector<SubstitutionArg> args; + std::map<std::string, BaseType *> argument_mappings; + for (auto &p : get_substs ()) + { + if (p.needs_substitution ()) + { + const std::string &symbol = p.get_param_ty ()->get_symbol (); + auto it = argument_mappings.find (symbol); + bool have_mapping = it != argument_mappings.end (); + + if (have_mapping) + { + args.push_back (SubstitutionArg (&p, it->second)); + } + else + { + TyVar infer_var = TyVar::get_implicit_infer_var (locus); + args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); + argument_mappings[symbol] = infer_var.get_tyty (); + } + } + else + { + args.push_back (SubstitutionArg (&p, p.get_param_ty ()->resolve ())); + } + } + + // FIXME do we need to add inference variables to all the possible bindings? + // it might just lead to inference variable hell not 100% sure if rustc does + // this i think the language might needs this to be explicitly set + + SubstitutionArgumentMappings infer_arguments (std::move (args), + {} /* binding_arguments */, + locus); + return handle_substitions (infer_arguments); +} + +SubstitutionArgumentMappings +SubstitutionRef::adjust_mappings_for_this ( + SubstitutionArgumentMappings &mappings) +{ + std::vector<SubstitutionArg> resolved_mappings; + for (size_t i = 0; i < substitutions.size (); i++) + { + auto &subst = substitutions.at (i); + + SubstitutionArg arg = SubstitutionArg::error (); + if (mappings.size () == substitutions.size ()) + { + mappings.get_argument_at (i, &arg); + } + else + { + if (subst.needs_substitution ()) + { + // get from passed in mappings + mappings.get_argument_for_symbol (subst.get_param_ty (), &arg); + } + else + { + // we should already have this somewhere + used_arguments.get_argument_for_symbol (subst.get_param_ty (), + &arg); + } + } + + bool ok = !arg.is_error (); + if (ok) + { + SubstitutionArg adjusted (&subst, arg.get_tyty ()); + resolved_mappings.push_back (std::move (adjusted)); + } + } + + if (resolved_mappings.empty ()) + return SubstitutionArgumentMappings::error (); + + return SubstitutionArgumentMappings (resolved_mappings, + mappings.get_binding_args (), + mappings.get_locus (), + mappings.get_subst_cb (), + mappings.trait_item_mode ()); +} + +bool +SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings &mappings) +{ + std::vector<SubstitutionArg> resolved_mappings; + for (size_t i = 0; i < substitutions.size (); i++) + { + auto &subst = substitutions.at (i); + + SubstitutionArg arg = SubstitutionArg::error (); + if (mappings.size () == substitutions.size ()) + { + mappings.get_argument_at (i, &arg); + } + else + { + if (subst.needs_substitution ()) + { + // get from passed in mappings + mappings.get_argument_for_symbol (subst.get_param_ty (), &arg); + } + else + { + // we should already have this somewhere + used_arguments.get_argument_for_symbol (subst.get_param_ty (), + &arg); + } + } + + bool ok = !arg.is_error (); + if (ok) + { + SubstitutionArg adjusted (&subst, arg.get_tyty ()); + resolved_mappings.push_back (std::move (adjusted)); + } + } + + return !resolved_mappings.empty (); +} + +// this function assumes that the mappings being passed are for the same type as +// this new substitution reference so ordering matters here +SubstitutionArgumentMappings +SubstitutionRef::solve_mappings_from_receiver_for_self ( + SubstitutionArgumentMappings &mappings) const +{ + std::vector<SubstitutionArg> resolved_mappings; + + rust_assert (mappings.size () == get_num_substitutions ()); + for (size_t i = 0; i < get_num_substitutions (); i++) + { + const SubstitutionParamMapping ¶m_mapping = substitutions.at (i); + SubstitutionArg &arg = mappings.get_mappings ().at (i); + + if (param_mapping.needs_substitution ()) + { + SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ()); + resolved_mappings.push_back (std::move (adjusted)); + } + } + + return SubstitutionArgumentMappings (resolved_mappings, + mappings.get_binding_args (), + mappings.get_locus ()); +} + +SubstitutionArgumentMappings +SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref, + SubstitutionRef &to) +{ + rust_assert (!ref.needs_substitution ()); + rust_assert (needs_substitution ()); + rust_assert (get_num_substitutions () == ref.get_num_substitutions ()); + + Location locus = used_arguments.get_locus (); + std::vector<SubstitutionArg> resolved_mappings; + + std::map<HirId, std::pair<ParamType *, BaseType *>> substs; + for (size_t i = 0; i < get_num_substitutions (); i++) + { + SubstitutionParamMapping &a = substitutions.at (i); + SubstitutionParamMapping &b = ref.substitutions.at (i); + + if (a.need_substitution ()) + { + const BaseType *root = a.get_param_ty ()->resolve ()->get_root (); + rust_assert (root->get_kind () == TyTy::TypeKind::PARAM); + const ParamType *p = static_cast<const TyTy::ParamType *> (root); + + substs[p->get_ty_ref ()] = {static_cast<ParamType *> (p->clone ()), + b.get_param_ty ()->resolve ()}; + } + } + + for (auto it = substs.begin (); it != substs.end (); it++) + { + HirId param_id = it->first; + BaseType *arg = it->second.second; + + const SubstitutionParamMapping *associate_param = nullptr; + for (SubstitutionParamMapping &p : to.substitutions) + { + if (p.get_param_ty ()->get_ty_ref () == param_id) + { + associate_param = &p; + break; + } + } + + rust_assert (associate_param != nullptr); + SubstitutionArg argument (associate_param, arg); + resolved_mappings.push_back (std::move (argument)); + } + + return SubstitutionArgumentMappings (resolved_mappings, {}, locus); +} + +Resolver::AssociatedImplTrait * +SubstitutionRef::lookup_associated_impl (const SubstitutionParamMapping &subst, + const TypeBoundPredicate &bound, + const TyTy::BaseType *binding, + bool *error_flag) const +{ + auto context = Resolver::TypeCheckContext::get (); + const Resolver::TraitReference *specified_bound_ref = bound.get (); + + // setup any associated type mappings for the specified bonds and this + // type + auto candidates = Resolver::TypeBoundsProbe::Probe (binding); + std::vector<Resolver::AssociatedImplTrait *> associated_impl_traits; + for (auto &probed_bound : candidates) + { + const Resolver::TraitReference *bound_trait_ref = probed_bound.first; + const HIR::ImplBlock *associated_impl = probed_bound.second; + + HirId impl_block_id = associated_impl->get_mappings ().get_hirid (); + Resolver::AssociatedImplTrait *associated = nullptr; + bool found_impl_trait + = context->lookup_associated_trait_impl (impl_block_id, &associated); + if (found_impl_trait) + { + bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref); + bool found_self = associated->get_self ()->can_eq (binding, false); + if (found_trait && found_self) + { + associated_impl_traits.push_back (associated); + } + } + } + + if (associated_impl_traits.empty ()) + return nullptr; + + // This code is important when you look at slices for example when + // you have a slice such as: + // + // let slice = &array[1..3] + // + // the higher ranked bounds will end up having an Index trait + // implementation for Range<usize> so we need this code to resolve + // that we have an integer inference variable that needs to become + // a usize + // + // The other complicated issue is that we might have an intrinsic + // which requires the :Clone or Copy bound but the libcore adds + // implementations for all the integral types so when there are + // multiple candidates we need to resolve to the default + // implementation for that type otherwise its an error for + // ambiguous type bounds + + // if we have a non-general inference variable we need to be + // careful about the selection here + bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER; + bool is_integer_infervar + = is_infer_var + && static_cast<const TyTy::InferType *> (binding)->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL; + bool is_float_infervar + = is_infer_var + && static_cast<const TyTy::InferType *> (binding)->get_infer_kind () + == TyTy::InferType::InferTypeKind::FLOAT; + + Resolver::AssociatedImplTrait *associate_impl_trait = nullptr; + if (associated_impl_traits.size () == 1) + { + // just go for it + associate_impl_trait = associated_impl_traits.at (0); + } + else if (is_integer_infervar) + { + TyTy::BaseType *type = nullptr; + bool ok = context->lookup_builtin ("i32", &type); + rust_assert (ok); + + for (auto &impl : associated_impl_traits) + { + bool found = impl->get_self ()->is_equal (*type); + if (found) + { + associate_impl_trait = impl; + break; + } + } + } + else if (is_float_infervar) + { + TyTy::BaseType *type = nullptr; + bool ok = context->lookup_builtin ("f64", &type); + rust_assert (ok); + + for (auto &impl : associated_impl_traits) + { + bool found = impl->get_self ()->is_equal (*type); + if (found) + { + associate_impl_trait = impl; + break; + } + } + } + + if (associate_impl_trait == nullptr) + { + // go for the first one? or error out? + auto &mappings = *Analysis::Mappings::get (); + const auto &type_param = subst.get_generic_param (); + const auto *trait_ref = bound.get (); + + RichLocation r (type_param.get_locus ()); + r.add_range (bound.get_locus ()); + r.add_range (mappings.lookup_location (binding->get_ref ())); + + rust_error_at (r, "ambiguous type bound for trait %s and type %s", + trait_ref->get_name ().c_str (), + binding->get_name ().c_str ()); + + *error_flag = true; + return nullptr; + } + + return associate_impl_trait; +} + +void +SubstitutionRef::prepare_higher_ranked_bounds () +{ + for (const auto &subst : get_substs ()) + { + const TyTy::ParamType *pty = subst.get_param_ty (); + for (const auto &bound : pty->get_specified_bounds ()) + { + const auto ref = bound.get (); + ref->clear_associated_type_projections (); + } + } +} + +bool +SubstitutionRef::monomorphize () +{ + for (const auto &subst : get_substs ()) + { + const TyTy::ParamType *pty = subst.get_param_ty (); + + if (!pty->can_resolve ()) + continue; + + const TyTy::BaseType *binding = pty->resolve (); + if (binding->get_kind () == TyTy::TypeKind::PARAM) + continue; + + for (const auto &bound : pty->get_specified_bounds ()) + { + bool error_flag = false; + auto associated + = lookup_associated_impl (subst, bound, binding, &error_flag); + if (associated != nullptr) + { + associated->setup_associated_types (binding, bound); + } + + if (error_flag) + return false; + } + } + + return true; +} + +} // namespace TyTy +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h new file mode 100644 index 0000000..365fdb6 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -0,0 +1,327 @@ +// Copyright (C) 2020-2023 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_SUBST_H +#define RUST_TYTY_SUBST_H + +#include "rust-system.h" +#include "rust-location.h" +#include "rust-hir-full-decls.h" +#include "rust-tyty-bounds.h" + +namespace Rust { +namespace TyTy { + +class BaseType; +class ParamType; +class SubstitutionArgumentMappings; +class SubstitutionParamMapping +{ +public: + SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param); + + SubstitutionParamMapping (const SubstitutionParamMapping &other); + + std::string as_string () const; + + bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings, + Location locus); + + SubstitutionParamMapping clone () const; + + ParamType *get_param_ty (); + + const ParamType *get_param_ty () const; + + const HIR::TypeParam &get_generic_param () const; + + // this is used for the backend to override the HirId ref of the param to + // what the concrete type is for the rest of the context + void override_context (); + + bool needs_substitution () const; + + Location get_param_locus () const; + + bool param_has_default_ty () const; + + BaseType *get_default_ty () const; + + bool need_substitution () const; + +private: + const HIR::TypeParam &generic; + ParamType *param; +}; + +class SubstitutionArg +{ +public: + SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument); + + // FIXME + // the copy constructors need removed - they are unsafe see + // TypeBoundPredicate + SubstitutionArg (const SubstitutionArg &other); + + SubstitutionArg &operator= (const SubstitutionArg &other); + + BaseType *get_tyty (); + + const BaseType *get_tyty () const; + + const SubstitutionParamMapping *get_param_mapping () const; + + static SubstitutionArg error (); + + bool is_error () const; + + bool is_conrete () const; + + std::string as_string () const; + +private: + const SubstitutionParamMapping *param; + BaseType *argument; +}; + +typedef std::function<void (const ParamType &, const SubstitutionArg &)> + ParamSubstCb; +class SubstitutionArgumentMappings +{ +public: + SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings, + std::map<std::string, BaseType *> binding_args, + Location locus, + ParamSubstCb param_subst_cb = nullptr, + bool trait_item_flag = false); + + SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other); + SubstitutionArgumentMappings & + operator= (const SubstitutionArgumentMappings &other); + + SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default; + SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other) + = default; + + static SubstitutionArgumentMappings error (); + + bool is_error () const; + + bool get_argument_for_symbol (const ParamType *param_to_find, + SubstitutionArg *argument); + + bool get_argument_at (size_t index, SubstitutionArg *argument); + + // 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; + + Location get_locus () const; + + size_t size () const; + + bool is_empty () const; + + std::vector<SubstitutionArg> &get_mappings (); + + const std::vector<SubstitutionArg> &get_mappings () const; + + std::map<std::string, BaseType *> &get_binding_args (); + + const std::map<std::string, BaseType *> &get_binding_args () const; + + std::string as_string () const; + + void on_param_subst (const ParamType &p, const SubstitutionArg &a) const; + + ParamSubstCb get_subst_cb () const; + + bool trait_item_mode () const; + +private: + std::vector<SubstitutionArg> mappings; + std::map<std::string, BaseType *> binding_args; + Location locus; + ParamSubstCb param_subst_cb; + bool trait_item_flag; +}; + +class SubstitutionRef +{ +public: + SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions, + SubstitutionArgumentMappings arguments); + + bool has_substitutions () const; + + std::string subst_as_string () const; + + bool supports_associated_bindings () const; + + // this is overridden in TypeBoundPredicate + // which support bindings we don't add them directly to the SubstitutionRef + // base class because this class represents the fn<X: Foo, Y: Bar>. The only + // construct which supports associated types + virtual size_t get_num_associated_bindings () const; + + // this is overridden in TypeBoundPredicate + virtual TypeBoundPredicateItem + lookup_associated_type (const std::string &search); + + size_t get_num_substitutions () const; + + std::vector<SubstitutionParamMapping> &get_substs (); + + const std::vector<SubstitutionParamMapping> &get_substs () const; + + std::vector<SubstitutionParamMapping> clone_substs () const; + + void override_context (); + + bool needs_substitution () const; + + bool was_substituted () const; + + SubstitutionArgumentMappings &get_substitution_arguments (); + const SubstitutionArgumentMappings &get_substitution_arguments () const; + + // this is the count of type params that are not substituted fuly + size_t num_required_substitutions () const; + + // this is the count of type params that need substituted taking into account + // possible defaults + size_t min_required_substitutions () const; + + // We are trying to subst <i32, f32> into Struct Foo<X,Y> {} + // in the case of Foo<i32,f32>{...} + // + // the substitions we have here define X,Y but the arguments have no bindings + // so its a matter of ordering + SubstitutionArgumentMappings + get_mappings_from_generic_args (HIR::GenericArgs &args); + + // Recursive substitutions + // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>} + // + // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo + // Which binds to A,B + SubstitutionArgumentMappings + adjust_mappings_for_this (SubstitutionArgumentMappings &mappings); + + // Are the mappings here actually bound to this type. For example imagine the + // case: + // + // struct Foo<T>(T); + // impl<T> Foo<T> { + // fn test(self) { ... } + // } + // + // In this case we have a generic ADT of Foo and an impl block of a generic T + // on Foo for the Self type. When we it comes to path resolution we can have: + // + // Foo::<i32>::test() + // + // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the + // Self ADT bound to the T from the impl block. This means when it comes to + // the next segment of test which resolves to the function we need to check + // wether the arguments in the struct definition of foo can be bound here + // before substituting the previous segments type here. This functions acts as + // a guard for the solve_mappings_from_receiver_for_self to handle the case + // where arguments are not bound. This is important for this next case: + // + // struct Baz<A, B>(A, B); + // impl Baz<i32, f32> { + // fn test<X>(a: X) -> X { + // a + // } + // } + // + // In this case Baz has been already substituted for the impl's Self to become + // ADT<i32, f32> so that the function test only has 1 generic argument of X. + // The path for this will be: + // + // Baz::test::<_>(123) + // + // So the first segment here will be Baz<_, _> to try and infer the arguments + // which will be taken from the impl's Self type in this case since it is + // already substituted and like the previous case the check to see if we need + // to inherit the previous segments generic arguments takes place but the + // generic arguments are not bound to this type as they have already been + // substituted. + // + // Its important to remember from the first example the FnType actually looks + // like: + // + // fn <T>test(self :Foo<T>(T)) + // + // As the generic parameters are "bound" to each of the items in the impl + // block. So this check is about wether the arguments we have here can + // actually be bound to this type. + bool are_mappings_bound (SubstitutionArgumentMappings &mappings); + + // struct Foo<A, B>(A, B); + // + // impl<T> Foo<T, f32>; + // -> fn test<X>(self, a: X) -> X + // + // We might invoke this via: + // + // a = Foo(123, 456f32); + // b = a.test::<bool>(false); + // + // we need to figure out relevant generic arguemts for self to apply to the + // fntype + SubstitutionArgumentMappings solve_mappings_from_receiver_for_self ( + SubstitutionArgumentMappings &mappings) const; + + // TODO comment + SubstitutionArgumentMappings + solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to); + + // TODO comment + BaseType *infer_substitions (Location locus); + + // this clears any possible projections from higher ranked trait bounds which + // could be hanging around from a previous resolution + void prepare_higher_ranked_bounds (); + + // FIXME + // this is bad name for this, i think it should be something like + // compute-higher-ranked-bounds + bool monomorphize (); + + // TODO comment + virtual BaseType *handle_substitions (SubstitutionArgumentMappings &mappings) + = 0; + + SubstitutionArgumentMappings get_used_arguments () const; + +protected: + Resolver::AssociatedImplTrait *lookup_associated_impl ( + const SubstitutionParamMapping &subst, const TypeBoundPredicate &bound, + const TyTy::BaseType *binding, bool *error_flag) const; + + std::vector<SubstitutionParamMapping> substitutions; + SubstitutionArgumentMappings used_arguments; +}; + +} // namespace TyTy +} // namespace Rust +#endif // RUST_TYTY_SUBST_H diff --git a/gcc/rust/typecheck/rust-tyty-util.cc b/gcc/rust/typecheck/rust-tyty-util.cc new file mode 100644 index 0000000..32b94f0 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-util.cc @@ -0,0 +1,116 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-hir-type-check.h" +#include "rust-tyty.h" + +namespace Rust { +namespace TyTy { + +TyVar::TyVar (HirId ref) : ref (ref) +{ + // ensure this reference is defined within the context + auto context = Resolver::TypeCheckContext::get (); + BaseType *lookup = nullptr; + bool ok = context->lookup_type (ref, &lookup); + rust_assert (ok); +} + +BaseType * +TyVar::get_tyty () const +{ + auto context = Resolver::TypeCheckContext::get (); + BaseType *lookup = nullptr; + bool ok = context->lookup_type (ref, &lookup); + rust_assert (ok); + return lookup; +} + +TyVar +TyVar::get_implicit_infer_var (Location locus) +{ + auto mappings = Analysis::Mappings::get (); + auto context = Resolver::TypeCheckContext::get (); + + InferType *infer = new InferType (mappings->get_next_hir_id (), + InferType::InferTypeKind::GENERAL, locus); + context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), + UNKNOWN_NODEID, + infer->get_ref (), + UNKNOWN_LOCAL_DEFID), + infer); + mappings->insert_location (infer->get_ref (), locus); + + return TyVar (infer->get_ref ()); +} + +TyVar +TyVar::subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst) +{ + if (orig->get_kind () != TyTy::TypeKind::PARAM) + return TyVar (subst->get_ty_ref ()); + else if (subst->get_kind () == TyTy::TypeKind::PARAM) + { + TyTy::ParamType *p = static_cast<TyTy::ParamType *> (subst); + if (p->resolve ()->get_kind () == TyTy::TypeKind::PARAM) + { + return TyVar (subst->get_ty_ref ()); + } + } + + return TyVar (subst->get_ref ()); +} + +TyVar +TyVar::clone () const +{ + TyTy::BaseType *c = get_tyty ()->clone (); + return TyVar (c->get_ref ()); +} + +TyVar +TyVar::monomorphized_clone () const +{ + auto mappings = Analysis::Mappings::get (); + auto context = Resolver::TypeCheckContext::get (); + + // this needs a new hirid + TyTy::BaseType *c = get_tyty ()->monomorphized_clone (); + c->set_ref (mappings->get_next_hir_id ()); + + // insert it + context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), + UNKNOWN_NODEID, c->get_ref (), + UNKNOWN_LOCAL_DEFID), + c); + + return TyVar (c->get_ref ()); +} + +TyWithLocation::TyWithLocation (BaseType *ty, Location locus) + : ty (ty), locus (locus) +{} + +TyWithLocation::TyWithLocation (BaseType *ty) : ty (ty) +{ + auto mappings = Analysis::Mappings::get (); + locus = mappings->lookup_location (ty->get_ref ()); +} + +} // namespace TyTy +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-util.h b/gcc/rust/typecheck/rust-tyty-util.h new file mode 100644 index 0000000..6b28379 --- /dev/null +++ b/gcc/rust/typecheck/rust-tyty-util.h @@ -0,0 +1,69 @@ +// Copyright (C) 2020-2023 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_UTIL_H +#define RUST_TYTY_UTIL_H + +#include "rust-hir-map.h" + +namespace Rust { +namespace TyTy { + +class BaseType; + +// this is a placeholder for types that can change like inference variables +class TyVar +{ +public: + explicit TyVar (HirId ref); + + HirId get_ref () const { return ref; } + + BaseType *get_tyty () const; + + TyVar clone () const; + + TyVar monomorphized_clone () const; + + static TyVar get_implicit_infer_var (Location locus); + + static TyVar subst_covariant_var (TyTy::BaseType *orig, + TyTy::BaseType *subst); + +private: + HirId ref; +}; + +class TyWithLocation +{ +public: + explicit TyWithLocation (BaseType *ty, Location locus); + explicit TyWithLocation (BaseType *ty); + + BaseType *get_ty () const { return ty; } + Location get_locus () const { return locus; } + +private: + BaseType *ty; + Location locus; +}; + +} // namespace TyTy +} // namespace Rust + +#endif // RUST_TYTY_UTIL_H diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 71f0de1..d0d36ac 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -17,17 +17,22 @@ // <http://www.gnu.org/licenses/>. #include "rust-tyty.h" -#include "rust-tyty-visitor.h" -#include "rust-tyty-call.h" + #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-tyty-visitor.h" +#include "rust-tyty-call.h" #include "rust-hir-map.h" +#include "rust-location.h" +#include "rust-linemap.h" + #include "rust-substitution-mapper.h" -#include "rust-hir-trait-ref.h" +#include "rust-hir-trait-reference.h" #include "rust-hir-type-bounds.h" #include "rust-hir-trait-resolve.h" +#include "rust-tyty-cmp.h" +#include "rust-type-util.h" + #include "options.h" namespace Rust { @@ -146,6 +151,123 @@ is_primitive_type_kind (TypeKind kind) } } +// BASE TYPE + +BaseType::BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, + std::set<HirId> refs) + : TypeBoundsMappings ({}), kind (kind), ref (ref), ty_ref (ty_ref), + combined (refs), ident (ident), mappings (Analysis::Mappings::get ()) +{} + +BaseType::BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : TypeBoundsMappings (specified_bounds), kind (kind), ref (ref), + ty_ref (ty_ref), combined (refs), ident (ident), + mappings (Analysis::Mappings::get ()) +{} + +BaseType::~BaseType () {} + +HirId +BaseType::get_ref () const +{ + return ref; +} + +void +BaseType::set_ref (HirId id) +{ + if (id != ref) + append_reference (ref); + ref = id; +} + +HirId +BaseType::get_ty_ref () const +{ + return ty_ref; +} + +void +BaseType::set_ty_ref (HirId id) +{ + ty_ref = id; +} + +bool +BaseType::is_equal (const BaseType &other) const +{ + return get_kind () == other.get_kind (); +} + +bool +BaseType::is_unit () const +{ + return false; +} + +TypeKind +BaseType::get_kind () const +{ + return kind; +} + +std::set<HirId> +BaseType::get_combined_refs () const +{ + return combined; +} + +void +BaseType::append_reference (HirId id) +{ + combined.insert (id); +} + +bool +BaseType::supports_substitutions () const +{ + return false; +} + +bool +BaseType::has_subsititions_defined () const +{ + return false; +} + +bool +BaseType::can_substitute () const +{ + return supports_substitutions () && has_subsititions_defined (); +} + +bool +BaseType::needs_generic_substitutions () const +{ + return false; +} + +bool +BaseType::contains_type_parameters () const +{ + return !is_concrete (); +} + +const RustIdent & +BaseType::get_ident () const +{ + return ident; +} + +Location +BaseType::get_locus () const +{ + return ident.locus; +} + +// FIXME this is missing locus bool BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const { @@ -157,12 +279,67 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const return true; } + bool satisfied = false; auto probed = Resolver::TypeBoundsProbe::Probe (this); for (const auto &b : probed) { const Resolver::TraitReference *bound = b.first; if (bound->satisfies_bound (*query)) + { + satisfied = true; + break; + } + } + + if (!satisfied) + return false; + + for (const auto &b : probed) + { + const Resolver::TraitReference *bound = b.first; + if (!bound->is_equal (*query)) + continue; + + // builtin ones have no impl-block this needs fixed and use a builtin node + // of somekind + if (b.second == nullptr) return true; + + // need to check that associated types can match as well + const HIR::ImplBlock &impl = *(b.second); + for (const auto &item : impl.get_impl_items ()) + { + TyTy::BaseType *impl_item_ty = nullptr; + Analysis::NodeMapping i = item->get_impl_mappings (); + bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty); + if (!query_ok) + return false; + + std::string item_name = item->get_impl_item_name (); + TypeBoundPredicateItem lookup + = predicate.lookup_associated_item (item_name); + if (lookup.is_error ()) + return false; + + const auto *item_ref = lookup.get_raw_item (); + TyTy::BaseType *bound_ty = item_ref->get_tyty (); + + // compare the types + if (!bound_ty->can_eq (impl_item_ty, false)) + { + RichLocation r (mappings->lookup_location (get_ref ())); + r.add_range (predicate.get_locus ()); + r.add_range (mappings->lookup_location (i.get_hirid ())); + + rust_error_at ( + r, "expected %<%s%> got %<%s%>", + bound_ty->destructure ()->get_name ().c_str (), + impl_item_ty->destructure ()->get_name ().c_str ()); + return false; + } + } + + return true; } return false; @@ -255,6 +432,58 @@ BaseType::get_root () const return root; } +BaseType * +BaseType::destructure () +{ + int recurisve_ops = 0; + BaseType *x = this; + while (true) + { + if (recurisve_ops++ >= rust_max_recursion_depth) + { + rust_error_at ( + Location (), + "%<recursion depth%> count exceeds limit of %i (use " + "%<frust-max-recursion-depth=%> to increase the limit)", + rust_max_recursion_depth); + return new ErrorType (get_ref ()); + } + + switch (x->get_kind ()) + { + case TyTy::TypeKind::PARAM: { + TyTy::ParamType *p = static_cast<TyTy::ParamType *> (x); + TyTy::BaseType *pr = p->resolve (); + if (pr == x) + return pr; + + x = pr; + } + break; + + case TyTy::TypeKind::PLACEHOLDER: { + TyTy::PlaceholderType *p = static_cast<TyTy::PlaceholderType *> (x); + if (!p->can_resolve ()) + return p; + + x = p->resolve (); + } + break; + + case TyTy::TypeKind::PROJECTION: { + TyTy::ProjectionType *p = static_cast<TyTy::ProjectionType *> (x); + x = p->get (); + } + break; + + default: + return x; + } + } + + return x; +} + const BaseType * BaseType::destructure () const { @@ -276,14 +505,20 @@ BaseType::destructure () const { case TyTy::TypeKind::PARAM: { const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (x); - x = p->resolve (); + const TyTy::BaseType *pr = p->resolve (); + if (pr == x) + return pr; + + x = pr; } break; case TyTy::TypeKind::PLACEHOLDER: { const TyTy::PlaceholderType *p = static_cast<const TyTy::PlaceholderType *> (x); - rust_assert (p->can_resolve ()); + if (!p->can_resolve ()) + return p; + x = p->resolve (); } break; @@ -330,94 +565,38 @@ BaseType::debug () const debug_str ().c_str ()); } -TyVar::TyVar (HirId ref) : ref (ref) -{ - // ensure this reference is defined within the context - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (ref, &lookup); - rust_assert (ok); -} - -BaseType * -TyVar::get_tyty () const -{ - auto context = Resolver::TypeCheckContext::get (); - BaseType *lookup = nullptr; - bool ok = context->lookup_type (ref, &lookup); - rust_assert (ok); - return lookup; -} - -TyVar -TyVar::get_implicit_infer_var (Location locus) -{ - auto mappings = Analysis::Mappings::get (); - auto context = Resolver::TypeCheckContext::get (); - - InferType *infer = new InferType (mappings->get_next_hir_id (), - InferType::InferTypeKind::GENERAL, locus); - context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), - UNKNOWN_NODEID, - infer->get_ref (), - UNKNOWN_LOCAL_DEFID), - infer); - mappings->insert_location (infer->get_ref (), locus); - - return TyVar (infer->get_ref ()); -} +// InferType -TyVar -TyVar::subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst) -{ - if (orig->get_kind () != TyTy::TypeKind::PARAM) - return TyVar (subst->get_ty_ref ()); - else if (subst->get_kind () == TyTy::TypeKind::PARAM) - { - TyTy::ParamType *p = static_cast<TyTy::ParamType *> (subst); - if (p->resolve ()->get_kind () == TyTy::TypeKind::PARAM) - { - return TyVar (subst->get_ty_ref ()); - } - } +InferType::InferType (HirId ref, InferTypeKind infer_kind, Location locus, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::INFER, + {Resolver::CanonicalPath::create_empty (), locus}, refs), + infer_kind (infer_kind) +{} - return TyVar (subst->get_ref ()); -} +InferType::InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind, + Location locus, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::INFER, + {Resolver::CanonicalPath::create_empty (), locus}, refs), + infer_kind (infer_kind) +{} -TyVar -TyVar::clone () const +InferType::InferTypeKind +InferType::get_infer_kind () const { - TyTy::BaseType *c = get_tyty ()->clone (); - return TyVar (c->get_ref ()); + return infer_kind; } -TyVar -TyVar::monomorphized_clone () const +std::string +InferType::get_name () const { - auto mappings = Analysis::Mappings::get (); - auto context = Resolver::TypeCheckContext::get (); - - // this needs a new hirid - TyTy::BaseType *c = get_tyty ()->monomorphized_clone (); - c->set_ref (mappings->get_next_hir_id ()); - - // insert it - context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), - UNKNOWN_NODEID, c->get_ref (), - UNKNOWN_LOCAL_DEFID), - c); - - return TyVar (c->get_ref ()); + return as_string (); } -TyWithLocation::TyWithLocation (BaseType *ty, Location locus) - : ty (ty), locus (locus) -{} - -TyWithLocation::TyWithLocation (BaseType *ty) : ty (ty) +bool +InferType::is_concrete () const { - auto mappings = Analysis::Mappings::get (); - locus = mappings->lookup_location (ty->get_ref ()); + return true; } void @@ -447,13 +626,6 @@ InferType::as_string () const return "<infer::error>"; } -BaseType * -InferType::unify (BaseType *other) -{ - InferRules r (this); - return r.unify (other); -} - bool InferType::can_eq (const BaseType *other, bool emit_errors) const { @@ -525,6 +697,35 @@ InferType::default_type (BaseType **type) const return false; } +// ErrorType + +ErrorType::ErrorType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::ERROR, + {Resolver::CanonicalPath::create_empty (), Location ()}, refs) +{} + +ErrorType::ErrorType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::ERROR, + {Resolver::CanonicalPath::create_empty (), Location ()}, refs) +{} + +bool +ErrorType::is_unit () const +{ + return true; +} +bool +ErrorType::is_concrete () const +{ + return false; +} + +std::string +ErrorType::get_name () const +{ + return as_string (); +} + void ErrorType::accept_vis (TyVisitor &vis) { @@ -543,12 +744,6 @@ ErrorType::as_string () const return "<tyty::error>"; } -BaseType * -ErrorType::unify (BaseType *other) -{ - return this; -} - bool ErrorType::can_eq (const BaseType *other, bool emit_errors) const { @@ -567,6 +762,55 @@ ErrorType::monomorphized_clone () const return clone (); } +// Struct Field type + +StructFieldType::StructFieldType (HirId ref, std::string name, BaseType *ty, + Location locus) + : ref (ref), name (name), ty (ty), locus (locus) +{} + +HirId +StructFieldType::get_ref () const +{ + return ref; +} + +std::string +StructFieldType::get_name () const +{ + return name; +} + +BaseType * +StructFieldType::get_field_type () const +{ + return ty; +} + +void +StructFieldType::set_field_type (BaseType *fty) +{ + ty = fty; +} + +bool +StructFieldType::is_concrete () const +{ + return ty->is_concrete (); +} + +void +StructFieldType::debug () const +{ + rust_debug ("%s", as_string ().c_str ()); +} + +Location +StructFieldType::get_locus () const +{ + return locus; +} + std::string StructFieldType::as_string () const { @@ -604,417 +848,241 @@ StructFieldType::monomorphized_clone () const get_field_type ()->monomorphized_clone (), locus); } -bool -SubstitutionParamMapping::need_substitution () const -{ - if (!param->can_resolve ()) - return true; - - auto resolved = param->resolve (); - return !resolved->is_concrete (); -} +// VariantDef -bool -SubstitutionParamMapping::fill_param_ty ( - SubstitutionArgumentMappings &subst_mappings, Location locus) +std::string +VariantDef::variant_type_string (VariantType type) { - SubstitutionArg arg = SubstitutionArg::error (); - bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg); - if (!ok) - return true; - - TyTy::BaseType &type = *arg.get_tyty (); - if (type.get_kind () == TyTy::TypeKind::INFER) + switch (type) { - type.inherit_bounds (*param); - } - else - { - if (!param->bounds_compatible (type, locus, true)) - return false; - } - - if (type.get_kind () == TypeKind::PARAM) - { - // delete param; - param = static_cast<ParamType *> (type.clone ()); - } - else - { - // check the substitution is compatible with bounds - if (!param->bounds_compatible (type, locus, true)) - return false; - - // recursively pass this down to all HRTB's - for (auto &bound : param->get_specified_bounds ()) - bound.handle_substitions (subst_mappings); - - param->set_ty_ref (type.get_ref ()); + case NUM: + return "enumeral"; + case TUPLE: + return "tuple"; + case STRUCT: + return "struct"; } - - return true; + gcc_unreachable (); + return ""; } -void -SubstitutionParamMapping::override_context () -{ - if (!param->can_resolve ()) - return; - - auto mappings = Analysis::Mappings::get (); - auto context = Resolver::TypeCheckContext::get (); +VariantDef::VariantDef (HirId id, DefId defid, std::string identifier, + RustIdent ident, HIR::Expr *discriminant) + : id (id), defid (defid), identifier (identifier), ident (ident), + discriminant (discriminant) - context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (), - UNKNOWN_NODEID, - param->get_ref (), - UNKNOWN_LOCAL_DEFID), - param->resolve ()); +{ + type = VariantType::NUM; + fields = {}; } -SubstitutionArgumentMappings -SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args) +VariantDef::VariantDef (HirId id, DefId defid, std::string identifier, + RustIdent ident, VariantType type, + HIR::Expr *discriminant, + std::vector<StructFieldType *> fields) + : id (id), defid (defid), identifier (identifier), ident (ident), type (type), + discriminant (discriminant), fields (fields) { - if (args.get_binding_args ().size () > 0) - { - RichLocation r (args.get_locus ()); - for (auto &binding : args.get_binding_args ()) - r.add_range (binding.get_locus ()); - - rust_error_at (r, "associated type bindings are not allowed here"); - return SubstitutionArgumentMappings::error (); - } - - // for inherited arguments - size_t offs = used_arguments.size (); - if (args.get_type_args ().size () + offs > substitutions.size ()) - { - RichLocation r (args.get_locus ()); - r.add_range (substitutions.front ().get_param_locus ()); - - rust_error_at ( - r, - "generic item takes at most %lu type arguments but %lu were supplied", - (unsigned long) substitutions.size (), - (unsigned long) args.get_type_args ().size ()); - return SubstitutionArgumentMappings::error (); - } - - if (args.get_type_args ().size () + offs < min_required_substitutions ()) - { - RichLocation r (args.get_locus ()); - r.add_range (substitutions.front ().get_param_locus ()); - - rust_error_at ( - r, - "generic item takes at least %lu type arguments but %lu were supplied", - (unsigned long) (min_required_substitutions () - offs), - (unsigned long) args.get_type_args ().size ()); - return SubstitutionArgumentMappings::error (); - } - - std::vector<SubstitutionArg> mappings = used_arguments.get_mappings (); - for (auto &arg : args.get_type_args ()) - { - BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ()); - if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (args.get_locus (), "failed to resolve type arguments"); - return SubstitutionArgumentMappings::error (); - } + rust_assert ((type == VariantType::NUM && fields.empty ()) + || (type == VariantType::TUPLE || type == VariantType::STRUCT)); +} - SubstitutionArg subst_arg (&substitutions.at (offs), resolved); - offs++; - mappings.push_back (std::move (subst_arg)); - } +VariantDef::VariantDef (const VariantDef &other) + : id (other.id), defid (other.defid), identifier (other.identifier), + ident (other.ident), type (other.type), discriminant (other.discriminant), + fields (other.fields) +{} - // we must need to fill out defaults - size_t left_over - = num_required_substitutions () - min_required_substitutions (); - if (left_over > 0) - { - for (size_t offs = mappings.size (); offs < substitutions.size (); offs++) - { - SubstitutionParamMapping ¶m = substitutions.at (offs); - rust_assert (param.param_has_default_ty ()); +VariantDef & +VariantDef::operator= (const VariantDef &other) +{ + id = other.id; + identifier = other.identifier; + type = other.type; + discriminant = other.discriminant; + fields = other.fields; + ident = other.ident; - BaseType *resolved = param.get_default_ty (); - if (resolved->get_kind () == TypeKind::ERROR) - return SubstitutionArgumentMappings::error (); + return *this; +} - // this resolved default might already contain default parameters - if (resolved->contains_type_parameters ()) - { - SubstitutionArgumentMappings intermediate (mappings, - args.get_locus ()); - resolved = Resolver::SubstMapperInternal::Resolve (resolved, - intermediate); +VariantDef & +VariantDef::get_error_node () +{ + static VariantDef node + = VariantDef (UNKNOWN_HIRID, UNKNOWN_DEFID, "", + {Resolver::CanonicalPath::create_empty (), + Linemap::unknown_location ()}, + nullptr); - if (resolved->get_kind () == TypeKind::ERROR) - return SubstitutionArgumentMappings::error (); - } + return node; +} - SubstitutionArg subst_arg (¶m, resolved); - mappings.push_back (std::move (subst_arg)); - } - } +bool +VariantDef::is_error () const +{ + return get_id () == UNKNOWN_HIRID; +} - return SubstitutionArgumentMappings (mappings, args.get_locus ()); +HirId +VariantDef::get_id () const +{ + return id; } -BaseType * -SubstitutionRef::infer_substitions (Location locus) +DefId +VariantDef::get_defid () const { - std::vector<SubstitutionArg> args; - std::map<std::string, BaseType *> argument_mappings; - for (auto &p : get_substs ()) - { - if (p.needs_substitution ()) - { - const std::string &symbol = p.get_param_ty ()->get_symbol (); - auto it = argument_mappings.find (symbol); - bool have_mapping = it != argument_mappings.end (); + return defid; +} - if (have_mapping) - { - args.push_back (SubstitutionArg (&p, it->second)); - } - else - { - TyVar infer_var = TyVar::get_implicit_infer_var (locus); - args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); - argument_mappings[symbol] = infer_var.get_tyty (); - } - } - else - { - args.push_back (SubstitutionArg (&p, p.get_param_ty ()->resolve ())); - } - } +VariantDef::VariantType +VariantDef::get_variant_type () const +{ + return type; +} - SubstitutionArgumentMappings infer_arguments (std::move (args), locus); - return handle_substitions (std::move (infer_arguments)); +bool +VariantDef::is_data_variant () const +{ + return type != VariantType::NUM; } -SubstitutionArgumentMappings -SubstitutionRef::adjust_mappings_for_this ( - SubstitutionArgumentMappings &mappings) +bool +VariantDef::is_dataless_variant () const { - std::vector<SubstitutionArg> resolved_mappings; - for (size_t i = 0; i < substitutions.size (); i++) - { - auto &subst = substitutions.at (i); + return type == VariantType::NUM; +} - SubstitutionArg arg = SubstitutionArg::error (); - if (mappings.size () == substitutions.size ()) - { - mappings.get_argument_at (i, &arg); - } - else - { - if (subst.needs_substitution ()) - { - // get from passed in mappings - mappings.get_argument_for_symbol (subst.get_param_ty (), &arg); - } - else - { - // we should already have this somewhere - used_arguments.get_argument_for_symbol (subst.get_param_ty (), - &arg); - } - } +std::string +VariantDef::get_identifier () const +{ + return identifier; +} - bool ok = !arg.is_error (); - if (ok) - { - SubstitutionArg adjusted (&subst, arg.get_tyty ()); - resolved_mappings.push_back (std::move (adjusted)); - } - } +size_t +VariantDef::num_fields () const +{ + return fields.size (); +} - if (resolved_mappings.empty ()) - return SubstitutionArgumentMappings::error (); +StructFieldType * +VariantDef::get_field_at_index (size_t index) +{ + rust_assert (index < fields.size ()); + return fields.at (index); +} - return SubstitutionArgumentMappings (resolved_mappings, mappings.get_locus (), - mappings.get_subst_cb (), - mappings.trait_item_mode ()); +std::vector<StructFieldType *> & +VariantDef::get_fields () +{ + rust_assert (type != NUM); + return fields; } bool -SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings &mappings) +VariantDef::lookup_field (const std::string &lookup, + StructFieldType **field_lookup, size_t *index) const { - std::vector<SubstitutionArg> resolved_mappings; - for (size_t i = 0; i < substitutions.size (); i++) + size_t i = 0; + for (auto &field : fields) { - auto &subst = substitutions.at (i); - - SubstitutionArg arg = SubstitutionArg::error (); - if (mappings.size () == substitutions.size ()) + if (field->get_name ().compare (lookup) == 0) { - mappings.get_argument_at (i, &arg); - } - else - { - if (subst.needs_substitution ()) - { - // get from passed in mappings - mappings.get_argument_for_symbol (subst.get_param_ty (), &arg); - } - else - { - // we should already have this somewhere - used_arguments.get_argument_for_symbol (subst.get_param_ty (), - &arg); - } - } + if (index != nullptr) + *index = i; - bool ok = !arg.is_error (); - if (ok) - { - SubstitutionArg adjusted (&subst, arg.get_tyty ()); - resolved_mappings.push_back (std::move (adjusted)); + if (field_lookup != nullptr) + *field_lookup = field; + + return true; } + i++; } + return false; +} - return !resolved_mappings.empty (); +HIR::Expr * +VariantDef::get_discriminant () const +{ + rust_assert (discriminant != nullptr); + return discriminant; } -// this function assumes that the mappings being passed are for the same type as -// this new substitution reference so ordering matters here -SubstitutionArgumentMappings -SubstitutionRef::solve_mappings_from_receiver_for_self ( - SubstitutionArgumentMappings &mappings) const +std::string +VariantDef::as_string () const { - std::vector<SubstitutionArg> resolved_mappings; + if (type == VariantType::NUM) + return identifier + " = " + discriminant->as_string (); - rust_assert (mappings.size () == get_num_substitutions ()); - for (size_t i = 0; i < get_num_substitutions (); i++) + std::string buffer; + for (size_t i = 0; i < fields.size (); ++i) { - const SubstitutionParamMapping ¶m_mapping = substitutions.at (i); - SubstitutionArg &arg = mappings.get_mappings ().at (i); - - if (param_mapping.needs_substitution ()) - { - SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ()); - resolved_mappings.push_back (std::move (adjusted)); - } + buffer += fields.at (i)->as_string (); + if ((i + 1) < fields.size ()) + buffer += ", "; } - return SubstitutionArgumentMappings (resolved_mappings, - mappings.get_locus ()); + if (type == VariantType::TUPLE) + return identifier + " (" + buffer + ")"; + else + return identifier + " {" + buffer + "}"; } -SubstitutionArgumentMappings -SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref, - SubstitutionRef &to) +bool +VariantDef::is_equal (const VariantDef &other) const { - rust_assert (!ref.needs_substitution ()); - rust_assert (needs_substitution ()); - rust_assert (get_num_substitutions () == ref.get_num_substitutions ()); - - Location locus = used_arguments.get_locus (); - std::vector<SubstitutionArg> resolved_mappings; + if (type != other.type) + return false; - std::map<HirId, std::pair<ParamType *, BaseType *>> substs; - for (size_t i = 0; i < get_num_substitutions (); i++) - { - SubstitutionParamMapping &a = substitutions.at (i); - SubstitutionParamMapping &b = ref.substitutions.at (i); + if (identifier.compare (other.identifier) != 0) + return false; - if (a.need_substitution ()) - { - const BaseType *root = a.get_param_ty ()->resolve ()->get_root (); - rust_assert (root->get_kind () == TyTy::TypeKind::PARAM); - const ParamType *p = static_cast<const TyTy::ParamType *> (root); + if (discriminant != other.discriminant) + return false; - substs[p->get_ty_ref ()] = {static_cast<ParamType *> (p->clone ()), - b.get_param_ty ()->resolve ()}; - } - } + if (fields.size () != other.fields.size ()) + return false; - for (auto it = substs.begin (); it != substs.end (); it++) + for (size_t i = 0; i < fields.size (); i++) { - HirId param_id = it->first; - BaseType *arg = it->second.second; - - const SubstitutionParamMapping *associate_param = nullptr; - for (SubstitutionParamMapping &p : to.substitutions) - { - if (p.get_param_ty ()->get_ty_ref () == param_id) - { - associate_param = &p; - break; - } - } - - rust_assert (associate_param != nullptr); - SubstitutionArg argument (associate_param, arg); - resolved_mappings.push_back (std::move (argument)); + if (!fields.at (i)->is_equal (*other.fields.at (i))) + return false; } - return SubstitutionArgumentMappings (resolved_mappings, locus); + return true; } -bool -SubstitutionRef::monomorphize () +VariantDef * +VariantDef::clone () const { - auto context = Resolver::TypeCheckContext::get (); - for (const auto &subst : get_substs ()) - { - const TyTy::ParamType *pty = subst.get_param_ty (); - - if (!pty->can_resolve ()) - continue; - - const TyTy::BaseType *binding = pty->resolve (); - if (binding->get_kind () == TyTy::TypeKind::PARAM) - continue; + std::vector<StructFieldType *> cloned_fields; + for (auto &f : fields) + cloned_fields.push_back ((StructFieldType *) f->clone ()); - for (const auto &bound : pty->get_specified_bounds ()) - { - const Resolver::TraitReference *specified_bound_ref = bound.get (); - - // setup any associated type mappings for the specified bonds and this - // type - auto candidates = Resolver::TypeBoundsProbe::Probe (binding); + return new VariantDef (id, defid, identifier, ident, type, discriminant, + cloned_fields); +} - Resolver::AssociatedImplTrait *associated_impl_trait = nullptr; - for (auto &probed_bound : candidates) - { - const Resolver::TraitReference *bound_trait_ref - = probed_bound.first; - const HIR::ImplBlock *associated_impl = probed_bound.second; - - HirId impl_block_id - = associated_impl->get_mappings ().get_hirid (); - Resolver::AssociatedImplTrait *associated = nullptr; - bool found_impl_trait - = context->lookup_associated_trait_impl (impl_block_id, - &associated); - if (found_impl_trait) - { - bool found_trait - = specified_bound_ref->is_equal (*bound_trait_ref); - bool found_self - = associated->get_self ()->can_eq (binding, false); - if (found_trait && found_self) - { - associated_impl_trait = associated; - break; - } - } - } +VariantDef * +VariantDef::monomorphized_clone () const +{ + std::vector<StructFieldType *> cloned_fields; + for (auto &f : fields) + cloned_fields.push_back ((StructFieldType *) f->monomorphized_clone ()); - if (associated_impl_trait != nullptr) - { - associated_impl_trait->setup_associated_types (binding, bound); - } - } - } + return new VariantDef (id, defid, identifier, ident, type, discriminant, + cloned_fields); +} - return true; +const RustIdent & +VariantDef::get_ident () const +{ + return ident; } +// ADTType + void ADTType::accept_vis (TyVisitor &vis) { @@ -1042,13 +1110,6 @@ ADTType::as_string () const return identifier + subst_as_string () + "{" + variants_buffer + "}"; } -BaseType * -ADTType::unify (BaseType *other) -{ - ADTRules r (this); - return r.unify (other); -} - bool ADTType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1181,7 +1242,7 @@ handle_substitions (SubstitutionArgumentMappings &subst_mappings, } ADTType * -ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) +ADTType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) { ADTType *adt = static_cast<ADTType *> (clone ()); adt->set_ty_ref (mappings->get_next_hir_id ()); @@ -1212,6 +1273,57 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) return adt; } +// TupleType + +TupleType::TupleType (HirId ref, Location locus, std::vector<TyVar> fields, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::TUPLE, + {Resolver::CanonicalPath::create_empty (), locus}, refs), + fields (fields) +{} + +TupleType::TupleType (HirId ref, HirId ty_ref, Location locus, + std::vector<TyVar> fields, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::TUPLE, + {Resolver::CanonicalPath::create_empty (), locus}, refs), + fields (fields) +{} + +TupleType * +TupleType::get_unit_type (HirId ref) +{ + return new TupleType (ref, Linemap::predeclared_location ()); +} + +bool +TupleType::is_unit () const +{ + return this->fields.empty (); +} + +size_t +TupleType::num_fields () const +{ + return fields.size (); +} + +bool +TupleType::is_concrete () const +{ + for (size_t i = 0; i < num_fields (); i++) + { + if (!get_field (i)->is_concrete ()) + return false; + } + return true; +} + +const std::vector<TyVar> & +TupleType::get_fields () const +{ + return fields; +} + void TupleType::accept_vis (TyVisitor &vis) { @@ -1260,13 +1372,6 @@ TupleType::get_field (size_t index) const return fields.at (index).get_tyty (); } -BaseType * -TupleType::unify (BaseType *other) -{ - TupleRules r (this); - return r.unify (other); -} - bool TupleType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1315,7 +1420,7 @@ TupleType::monomorphized_clone () const } TupleType * -TupleType::handle_substitions (SubstitutionArgumentMappings mappings) +TupleType::handle_substitions (SubstitutionArgumentMappings &mappings) { auto mappings_table = Analysis::Mappings::get (); @@ -1367,13 +1472,6 @@ FnType::as_string () const return "fn" + subst_as_string () + " (" + params_str + ") -> " + ret_str; } -BaseType * -FnType::unify (BaseType *other) -{ - FnRules r (this); - return r.unify (other); -} - bool FnType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1456,7 +1554,7 @@ FnType::monomorphized_clone () const } FnType * -FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) +FnType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) { FnType *fn = static_cast<FnType *> (clone ()); fn->set_ty_ref (mappings->get_next_hir_id ()); @@ -1598,13 +1696,6 @@ FnPtr::as_string () const return "fnptr (" + params_str + ") -> " + get_return_type ()->as_string (); } -BaseType * -FnPtr::unify (BaseType *other) -{ - FnptrRules r (this); - return r.unify (other); -} - bool FnPtr::can_eq (const BaseType *other, bool emit_errors) const { @@ -1678,13 +1769,6 @@ ClosureType::as_string () const return "|" + params_buf + "| {" + result_type.get_tyty ()->as_string () + "}"; } -BaseType * -ClosureType::unify (BaseType *other) -{ - ClosureRules r (this); - return r.unify (other); -} - bool ClosureType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1724,7 +1808,7 @@ ClosureType::monomorphized_clone () const } ClosureType * -ClosureType::handle_substitions (SubstitutionArgumentMappings mappings) +ClosureType::handle_substitions (SubstitutionArgumentMappings &mappings) { gcc_unreachable (); return nullptr; @@ -1794,13 +1878,6 @@ ArrayType::as_string () const return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]"; } -BaseType * -ArrayType::unify (BaseType *other) -{ - ArrayRules r (this); - return r.unify (other); -} - bool ArrayType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1844,7 +1921,7 @@ ArrayType::monomorphized_clone () const } ArrayType * -ArrayType::handle_substitions (SubstitutionArgumentMappings mappings) +ArrayType::handle_substitions (SubstitutionArgumentMappings &mappings) { auto mappings_table = Analysis::Mappings::get (); @@ -1877,13 +1954,6 @@ SliceType::as_string () const return "[" + get_element_type ()->as_string () + "]"; } -BaseType * -SliceType::unify (BaseType *other) -{ - SliceRules r (this); - return r.unify (other); -} - bool SliceType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1927,7 +1997,7 @@ SliceType::monomorphized_clone () const } SliceType * -SliceType::handle_substitions (SubstitutionArgumentMappings mappings) +SliceType::handle_substitions (SubstitutionArgumentMappings &mappings) { auto mappings_table = Analysis::Mappings::get (); @@ -1942,6 +2012,34 @@ SliceType::handle_substitions (SubstitutionArgumentMappings mappings) return ref; } +// BoolType + +BoolType::BoolType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::BOOL, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +BoolType::BoolType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::BOOL, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +std::string +BoolType::get_name () const +{ + return as_string (); +} + +bool +BoolType::is_concrete () const +{ + return true; +} + void BoolType::accept_vis (TyVisitor &vis) { @@ -1960,13 +2058,6 @@ BoolType::as_string () const return "bool"; } -BaseType * -BoolType::unify (BaseType *other) -{ - BoolRules r (this); - return r.unify (other); -} - bool BoolType::can_eq (const BaseType *other, bool emit_errors) const { @@ -1986,6 +2077,36 @@ BoolType::monomorphized_clone () const return clone (); } +// IntType + +IntType::IntType (HirId ref, IntKind kind, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::INT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + int_kind (kind) +{} + +IntType::IntType (HirId ref, HirId ty_ref, IntKind kind, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::INT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + int_kind (kind) +{} + +std::string +IntType::get_name () const +{ + return as_string (); +} + +IntType::IntKind +IntType::get_int_kind () const +{ + return int_kind; +} + void IntType::accept_vis (TyVisitor &vis) { @@ -2018,13 +2139,6 @@ IntType::as_string () const return "__unknown_int_type"; } -BaseType * -IntType::unify (BaseType *other) -{ - IntRules r (this); - return r.unify (other); -} - bool IntType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2055,6 +2169,43 @@ IntType::is_equal (const BaseType &other) const return get_int_kind () == o.get_int_kind (); } +bool +IntType::is_concrete () const +{ + return true; +} + +// UintType + +UintType::UintType (HirId ref, UintKind kind, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::UINT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + uint_kind (kind) +{} + +UintType::UintType (HirId ref, HirId ty_ref, UintKind kind, + std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::UINT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + uint_kind (kind) +{} + +std::string +UintType::get_name () const +{ + return as_string (); +} + +UintType::UintKind +UintType::get_uint_kind () const +{ + return uint_kind; +} + void UintType::accept_vis (TyVisitor &vis) { @@ -2087,13 +2238,6 @@ UintType::as_string () const return "__unknown_uint_type"; } -BaseType * -UintType::unify (BaseType *other) -{ - UintRules r (this); - return r.unify (other); -} - bool UintType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2124,6 +2268,49 @@ UintType::is_equal (const BaseType &other) const return get_uint_kind () == o.get_uint_kind (); } +bool +UintType::is_concrete () const +{ + return true; +} + +// FloatType + +FloatType::FloatType (HirId ref, FloatKind kind, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::FLOAT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + float_kind (kind) +{} + +FloatType::FloatType (HirId ref, HirId ty_ref, FloatKind kind, + std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::FLOAT, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + float_kind (kind) +{} + +std::string +FloatType::get_name () const +{ + return as_string (); +} + +FloatType::FloatKind +FloatType::get_float_kind () const +{ + return float_kind; +} + +bool +FloatType::is_concrete () const +{ + return true; +} + void FloatType::accept_vis (TyVisitor &vis) { @@ -2150,13 +2337,6 @@ FloatType::as_string () const return "__unknown_float_type"; } -BaseType * -FloatType::unify (BaseType *other) -{ - FloatRules r (this); - return r.unify (other); -} - bool FloatType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2187,6 +2367,34 @@ FloatType::is_equal (const BaseType &other) const return get_float_kind () == o.get_float_kind (); } +// UsizeType + +USizeType::USizeType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::USIZE, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +USizeType::USizeType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::USIZE, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +std::string +USizeType::get_name () const +{ + return as_string (); +} + +bool +USizeType::is_concrete () const +{ + return true; +} + void USizeType::accept_vis (TyVisitor &vis) { @@ -2205,13 +2413,6 @@ USizeType::as_string () const return "usize"; } -BaseType * -USizeType::unify (BaseType *other) -{ - USizeRules r (this); - return r.unify (other); -} - bool USizeType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2231,6 +2432,34 @@ USizeType::monomorphized_clone () const return clone (); } +// ISizeType + +ISizeType::ISizeType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::ISIZE, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +ISizeType::ISizeType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::ISIZE, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +std::string +ISizeType::get_name () const +{ + return as_string (); +} + +bool +ISizeType::is_concrete () const +{ + return true; +} + void ISizeType::accept_vis (TyVisitor &vis) { @@ -2249,13 +2478,6 @@ ISizeType::as_string () const return "isize"; } -BaseType * -ISizeType::unify (BaseType *other) -{ - ISizeRules r (this); - return r.unify (other); -} - bool ISizeType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2275,6 +2497,34 @@ ISizeType::monomorphized_clone () const return clone (); } +// Char Type + +CharType::CharType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::CHAR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +CharType::CharType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::CHAR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +bool +CharType::is_concrete () const +{ + return true; +} + +std::string +CharType::get_name () const +{ + return as_string (); +} + void CharType::accept_vis (TyVisitor &vis) { @@ -2293,13 +2543,6 @@ CharType::as_string () const return "char"; } -BaseType * -CharType::unify (BaseType *other) -{ - CharRules r (this); - return r.unify (other); -} - bool CharType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2319,6 +2562,76 @@ CharType::monomorphized_clone () const return clone (); } +// Reference Type + +ReferenceType::ReferenceType (HirId ref, TyVar base, Mutability mut, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::REF, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + base (base), mut (mut) +{} + +ReferenceType::ReferenceType (HirId ref, HirId ty_ref, TyVar base, + Mutability mut, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::REF, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + base (base), mut (mut) +{} + +bool +ReferenceType::is_concrete () const +{ + return get_base ()->is_concrete (); +} + +Mutability +ReferenceType::mutability () const +{ + return mut; +} + +bool +ReferenceType::is_mutable () const +{ + return mut == Mutability::Mut; +} + +bool +ReferenceType::is_dyn_object () const +{ + return is_dyn_slice_type () || is_dyn_str_type (); +} + +bool +ReferenceType::is_dyn_slice_type (const TyTy::SliceType **slice) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::SLICE) + return false; + if (slice == nullptr) + return true; + + *slice = static_cast<const TyTy::SliceType *> (element); + return true; +} + +bool +ReferenceType::is_dyn_str_type (const TyTy::StrType **str) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::STR) + return false; + if (str == nullptr) + return true; + + *str = static_cast<const TyTy::StrType *> (element); + return true; +} + void ReferenceType::accept_vis (TyVisitor &vis) { @@ -2345,13 +2658,6 @@ ReferenceType::get_name () const + get_base ()->get_name (); } -BaseType * -ReferenceType::unify (BaseType *other) -{ - ReferenceRules r (this); - return r.unify (other); -} - bool ReferenceType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2394,7 +2700,7 @@ ReferenceType::monomorphized_clone () const } ReferenceType * -ReferenceType::handle_substitions (SubstitutionArgumentMappings mappings) +ReferenceType::handle_substitions (SubstitutionArgumentMappings &mappings) { auto mappings_table = Analysis::Mappings::get (); @@ -2409,6 +2715,82 @@ ReferenceType::handle_substitions (SubstitutionArgumentMappings mappings) return ref; } +// PointerType + +PointerType::PointerType (HirId ref, TyVar base, Mutability mut, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::POINTER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + base (base), mut (mut) +{} + +PointerType::PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut, + std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::POINTER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + base (base), mut (mut) +{} + +bool +PointerType::is_concrete () const +{ + return get_base ()->is_concrete (); +} + +Mutability +PointerType::mutability () const +{ + return mut; +} + +bool +PointerType::is_mutable () const +{ + return mut == Mutability::Mut; +} + +bool +PointerType::is_const () const +{ + return mut == Mutability::Imm; +} + +bool +PointerType::is_dyn_object () const +{ + return is_dyn_slice_type () || is_dyn_str_type (); +} + +bool +PointerType::is_dyn_slice_type (const TyTy::SliceType **slice) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::SLICE) + return false; + if (slice == nullptr) + return true; + + *slice = static_cast<const TyTy::SliceType *> (element); + return true; +} + +bool +PointerType::is_dyn_str_type (const TyTy::StrType **str) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::STR) + return false; + if (str == nullptr) + return true; + + *str = static_cast<const TyTy::StrType *> (element); + return true; +} + void PointerType::accept_vis (TyVisitor &vis) { @@ -2435,13 +2817,6 @@ PointerType::get_name () const + get_base ()->get_name (); } -BaseType * -PointerType::unify (BaseType *other) -{ - PointerRules r (this); - return r.unify (other); -} - bool PointerType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2484,7 +2859,7 @@ PointerType::monomorphized_clone () const } PointerType * -PointerType::handle_substitions (SubstitutionArgumentMappings mappings) +PointerType::handle_substitions (SubstitutionArgumentMappings &mappings) { auto mappings_table = Analysis::Mappings::get (); @@ -2499,6 +2874,52 @@ PointerType::handle_substitions (SubstitutionArgumentMappings mappings) return ref; } +// PARAM Type + +ParamType::ParamType (std::string symbol, Location locus, HirId ref, + HIR::GenericParam ¶m, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::PARAM, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), + locus}, + specified_bounds, refs), + is_trait_self (false), symbol (symbol), param (param) +{} + +ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus, + HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::PARAM, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), + locus}, + specified_bounds, refs), + is_trait_self (is_trait_self), symbol (symbol), param (param) +{} + +HIR::GenericParam & +ParamType::get_generic_param () +{ + return param; +} + +bool +ParamType::can_resolve () const +{ + return get_ref () != get_ty_ref (); +} + +bool +ParamType::is_concrete () const +{ + auto r = resolve (); + if (r == this) + return false; + + return r->is_concrete (); +} + void ParamType::accept_vis (TyVisitor &vis) { @@ -2532,13 +2953,6 @@ ParamType::get_name () const return resolve ()->get_name (); } -BaseType * -ParamType::unify (BaseType *other) -{ - ParamRules r (this); - return r.unify (other); -} - bool ParamType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2549,8 +2963,9 @@ ParamType::can_eq (const BaseType *other, bool emit_errors) const BaseType * ParamType::clone () const { - return new ParamType (get_symbol (), ident.locus, get_ref (), get_ty_ref (), - param, get_specified_bounds (), get_combined_refs ()); + return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (), + get_ty_ref (), param, get_specified_bounds (), + get_combined_refs ()); } BaseType * @@ -2615,7 +3030,7 @@ ParamType::is_equal (const BaseType &other) const } ParamType * -ParamType::handle_substitions (SubstitutionArgumentMappings subst_mappings) +ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) { SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (this, &arg); @@ -2640,6 +3055,46 @@ ParamType::handle_substitions (SubstitutionArgumentMappings subst_mappings) return p; } +void +ParamType::set_implicit_self_trait () +{ + is_trait_self = true; +} + +bool +ParamType::is_implicit_self_trait () const +{ + return is_trait_self; +} + +// StrType + +StrType::StrType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::STR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +StrType::StrType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::STR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +std::string +StrType::get_name () const +{ + return as_string (); +} + +bool +StrType::is_concrete () const +{ + return true; +} + BaseType * StrType::clone () const { @@ -2670,13 +3125,6 @@ StrType::as_string () const return "str"; } -BaseType * -StrType::unify (BaseType *other) -{ - StrRules r (this); - return r.unify (other); -} - bool StrType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2690,6 +3138,40 @@ StrType::is_equal (const BaseType &other) const return get_kind () == other.get_kind (); } +// Never Type + +NeverType::NeverType (HirId ref, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::NEVER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +NeverType::NeverType (HirId ref, HirId ty_ref, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::NEVER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) +{} + +std::string +NeverType::get_name () const +{ + return as_string (); +} + +bool +NeverType::is_unit () const +{ + return true; +} + +bool +NeverType::is_concrete () const +{ + return true; +} + void NeverType::accept_vis (TyVisitor &vis) { @@ -2708,13 +3190,6 @@ NeverType::as_string () const return "!"; } -BaseType * -NeverType::unify (BaseType *other) -{ - NeverRules r (this); - return r.unify (other); -} - bool NeverType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2736,6 +3211,52 @@ NeverType::monomorphized_clone () const // placeholder type +PlaceholderType::PlaceholderType (std::string symbol, HirId ref, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::PLACEHOLDER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + symbol (symbol) +{} + +PlaceholderType::PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, + std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::PLACEHOLDER, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + symbol (symbol) +{} + +std::string +PlaceholderType::get_name () const +{ + return as_string (); +} + +bool +PlaceholderType::is_unit () const +{ + rust_assert (can_resolve ()); + return resolve ()->is_unit (); +} + +std::string +PlaceholderType::get_symbol () const +{ + return symbol; +} + +bool +PlaceholderType::is_concrete () const +{ + if (!can_resolve ()) + return true; + + return resolve ()->is_concrete (); +} + void PlaceholderType::accept_vis (TyVisitor &vis) { @@ -2755,13 +3276,6 @@ PlaceholderType::as_string () const + ">"; } -BaseType * -PlaceholderType::unify (BaseType *other) -{ - PlaceholderRules r (this); - return r.unify (other); -} - bool PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2835,6 +3349,78 @@ PlaceholderType::is_equal (const BaseType &other) const // Projection type +ProjectionType::ProjectionType ( + HirId ref, BaseType *base, const Resolver::TraitReference *trait, DefId item, + std::vector<SubstitutionParamMapping> subst_refs, + SubstitutionArgumentMappings generic_arguments, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::PROJECTION, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)), + base (base), trait (trait), item (item) +{} + +ProjectionType::ProjectionType ( + HirId ref, HirId ty_ref, BaseType *base, + const Resolver::TraitReference *trait, DefId item, + std::vector<SubstitutionParamMapping> subst_refs, + SubstitutionArgumentMappings generic_arguments, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::PROJECTION, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)), + base (base), trait (trait), item (item) +{} + +bool +ProjectionType::is_unit () const +{ + return false; +} + +std::string +ProjectionType::get_name () const +{ + return as_string (); +} + +bool +ProjectionType::needs_generic_substitutions () const +{ + return needs_substitution (); +} + +bool +ProjectionType::supports_substitutions () const +{ + return true; +} + +bool +ProjectionType::has_subsititions_defined () const +{ + return has_substitutions (); +} + +const BaseType * +ProjectionType::get () const +{ + return base; +} +BaseType * +ProjectionType::get () +{ + return base; +} + +bool +ProjectionType::is_concrete () const +{ + return base->is_concrete (); +} + void ProjectionType::accept_vis (TyVisitor &vis) { @@ -2853,12 +3439,6 @@ ProjectionType::as_string () const return "<Projection=" + subst_as_string () + "::" + base->as_string () + ">"; } -BaseType * -ProjectionType::unify (BaseType *other) -{ - return base->unify (other); -} - bool ProjectionType::can_eq (const BaseType *other, bool emit_errors) const { @@ -2880,7 +3460,8 @@ ProjectionType::monomorphized_clone () const } ProjectionType * -ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings) +ProjectionType::handle_substitions ( + SubstitutionArgumentMappings &subst_mappings) { // // do we really need to substitute this? // if (base->needs_generic_substitutions () || base->contains_type_parameters @@ -2951,6 +3532,26 @@ ProjectionType::handle_substitions (SubstitutionArgumentMappings subst_mappings) return projection; } +// DynObjectType + +DynamicObjectType::DynamicObjectType ( + HirId ref, RustIdent ident, std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::DYNAMIC, ident, specified_bounds, refs) +{} + +DynamicObjectType::DynamicObjectType ( + HirId ref, HirId ty_ref, RustIdent ident, + std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::DYNAMIC, ident, specified_bounds, refs) +{} + +bool +DynamicObjectType::is_concrete () const +{ + return true; +} + void DynamicObjectType::accept_vis (TyVisitor &vis) { @@ -2969,13 +3570,6 @@ DynamicObjectType::as_string () const return "dyn [" + raw_bounds_as_string () + "]"; } -BaseType * -DynamicObjectType::unify (BaseType *other) -{ - DynamicRules r (this); - return r.unify (other); -} - bool DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 0fd664c..64b9379 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -20,11 +20,12 @@ #define RUST_TYTY #include "rust-hir-map.h" -#include "rust-hir-full.h" -#include "rust-diagnostics.h" -#include "rust-abi.h" #include "rust-common.h" #include "rust-identifier.h" +#include "rust-abi.h" +#include "rust-tyty-bounds.h" +#include "rust-tyty-util.h" +#include "rust-tyty-subst.h" namespace Rust { @@ -76,65 +77,6 @@ public: static std::string to_string (TypeKind kind); }; -class BaseType; -class TypeBoundPredicate; -class TypeBoundPredicateItem -{ -public: - TypeBoundPredicateItem (const TypeBoundPredicate *parent, - const Resolver::TraitItemReference *trait_item_ref) - : parent (parent), trait_item_ref (trait_item_ref) - {} - - static TypeBoundPredicateItem error () - { - return TypeBoundPredicateItem (nullptr, nullptr); - } - - bool is_error () const - { - return parent == nullptr || trait_item_ref == nullptr; - } - - BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); - - const Resolver::TraitItemReference *get_raw_item () const; - - bool needs_implementation () const; - - const TypeBoundPredicate *get_parent () const { return parent; } - - Location get_locus () const; - -private: - const TypeBoundPredicate *parent; - const Resolver::TraitItemReference *trait_item_ref; -}; - -class TypeBoundsMappings -{ -protected: - TypeBoundsMappings (std::vector<TypeBoundPredicate> specified_bounds); - -public: - std::vector<TypeBoundPredicate> &get_specified_bounds (); - - const std::vector<TypeBoundPredicate> &get_specified_bounds () const; - - size_t num_specified_bounds () const; - - std::string raw_bounds_as_string () const; - - std::string bounds_as_string () const; - - std::string raw_bounds_as_name () const; - -protected: - void add_bound (TypeBoundPredicate predicate); - - std::vector<TypeBoundPredicate> specified_bounds; -}; - extern void set_cmp_autoderef_mode (); extern void @@ -145,20 +87,15 @@ class TyConstVisitor; class BaseType : public TypeBoundsMappings { public: - virtual ~BaseType () {} + virtual ~BaseType (); - HirId get_ref () const { return ref; } + HirId get_ref () const; - void set_ref (HirId id) - { - if (id != ref) - append_reference (ref); - ref = id; - } + void set_ref (HirId id); - HirId get_ty_ref () const { return ty_ref; } + HirId get_ty_ref () const; - void set_ty_ref (HirId id) { ty_ref = id; } + void set_ty_ref (HirId id); virtual void accept_vis (TyVisitor &vis) = 0; @@ -168,11 +105,6 @@ 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. - virtual BaseType *unify (BaseType *other) = 0; - // similar to unify but does not actually perform type unification but // determines whether they are compatible. Consider the following // @@ -189,10 +121,7 @@ public: // 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 (); - } + virtual bool is_equal (const BaseType &other) const; bool satisfies_bound (const TypeBoundPredicate &predicate) const; @@ -204,11 +133,11 @@ public: void inherit_bounds ( const std::vector<TyTy::TypeBoundPredicate> &specified_bounds); - virtual bool is_unit () const { return false; } + virtual bool is_unit () const; virtual bool is_concrete () const = 0; - TypeKind get_kind () const { return kind; } + TypeKind get_kind () const; /* Returns a pointer to a clone of this. The caller is responsible for * releasing the memory of the returned ty. */ @@ -218,22 +147,19 @@ public: virtual BaseType *monomorphized_clone () const = 0; // get_combined_refs returns the chain of node refs involved in unification - std::set<HirId> get_combined_refs () const { return combined; } + std::set<HirId> get_combined_refs () const; - void append_reference (HirId id) { combined.insert (id); } + void append_reference (HirId id); - virtual bool supports_substitutions () const { return false; } + virtual bool supports_substitutions () const; - virtual bool has_subsititions_defined () const { return false; } + virtual bool has_subsititions_defined () const; - virtual bool can_substitute () const - { - return supports_substitutions () && has_subsititions_defined (); - } + virtual bool can_substitute () const; - virtual bool needs_generic_substitutions () const { return false; } + virtual bool needs_generic_substitutions () const; - bool contains_type_parameters () const { return !is_concrete (); } + bool contains_type_parameters () const; std::string mappings_str () const; @@ -246,26 +172,20 @@ public: // This will get the monomorphized type from Params, Placeholders or // Projections if available or error + BaseType *destructure (); const BaseType *destructure () const; - const RustIdent &get_ident () const { return ident; } + const RustIdent &get_ident () const; - Location get_locus () const { return ident.locus; } + Location get_locus () const; protected: BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, - std::set<HirId> refs = std::set<HirId> ()) - : TypeBoundsMappings ({}), kind (kind), ref (ref), ty_ref (ty_ref), - combined (refs), ident (ident), mappings (Analysis::Mappings::get ()) - {} + std::set<HirId> refs = std::set<HirId> ()); BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, std::vector<TypeBoundPredicate> specified_bounds, - std::set<HirId> refs = std::set<HirId> ()) - : TypeBoundsMappings (specified_bounds), kind (kind), ref (ref), - ty_ref (ty_ref), combined (refs), ident (ident), - mappings (Analysis::Mappings::get ()) - {} + std::set<HirId> refs = std::set<HirId> ()); TypeKind kind; HirId ref; @@ -276,43 +196,6 @@ protected: Analysis::Mappings *mappings; }; -// this is a placeholder for types that can change like inference variables -class TyVar -{ -public: - explicit TyVar (HirId ref); - - HirId get_ref () const { return ref; } - - BaseType *get_tyty () const; - - TyVar clone () const; - - TyVar monomorphized_clone () const; - - static TyVar get_implicit_infer_var (Location locus); - - static TyVar subst_covariant_var (TyTy::BaseType *orig, - TyTy::BaseType *subst); - -private: - HirId ref; -}; - -class TyWithLocation -{ -public: - explicit TyWithLocation (BaseType *ty, Location locus); - explicit TyWithLocation (BaseType *ty); - - BaseType *get_ty () const { return ty; } - Location get_locus () const { return locus; } - -private: - BaseType *ty; - Location locus; -}; - class InferType : public BaseType { public: @@ -324,38 +207,28 @@ public: }; InferType (HirId ref, InferTypeKind infer_kind, Location locus, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::INFER, - {Resolver::CanonicalPath::create_empty (), locus}, refs), - infer_kind (infer_kind) - {} + std::set<HirId> refs = std::set<HirId> ()); InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind, Location locus, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::INFER, - {Resolver::CanonicalPath::create_empty (), locus}, refs), - infer_kind (infer_kind) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; - bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - InferTypeKind get_infer_kind () const { return infer_kind; } + InferTypeKind get_infer_kind () const; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; bool default_type (BaseType **type) const; - bool is_concrete () const final override { return true; } + bool is_concrete () const final override; private: InferTypeKind infer_kind; @@ -364,66 +237,46 @@ private: class ErrorType : public BaseType { public: - ErrorType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::ERROR, - {Resolver::CanonicalPath::create_empty (), Location ()}, refs) - {} + ErrorType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); - ErrorType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::ERROR, - {Resolver::CanonicalPath::create_empty (), Location ()}, refs) - {} + ErrorType (HirId ref, HirId ty_ref, + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; - bool is_unit () const override { return true; } + bool is_unit () const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - bool is_concrete () const final override { return false; } + bool is_concrete () const final override; }; -class SubstitutionArgumentMappings; class ParamType : public BaseType { public: ParamType (std::string symbol, Location locus, HirId ref, HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::PARAM, - {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), - locus}, - specified_bounds, refs), - symbol (symbol), param (param) - {} + std::set<HirId> refs = std::set<HirId> ()); - ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref, - HIR::GenericParam ¶m, + ParamType (bool is_trait_self, std::string symbol, Location locus, HirId ref, + HirId ty_ref, HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::PARAM, - {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), - locus}, - specified_bounds, refs), - symbol (symbol), param (param) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; @@ -431,9 +284,9 @@ public: std::string get_symbol () const; - HIR::GenericParam &get_generic_param () { return param; } + HIR::GenericParam &get_generic_param (); - bool can_resolve () const { return get_ref () != get_ty_ref (); } + bool can_resolve () const; BaseType *resolve () const; @@ -441,18 +294,15 @@ public: bool is_equal (const BaseType &other) const override; - bool is_concrete () const override final - { - auto r = resolve (); - if (r == this) - return false; + bool is_concrete () const override final; - return r->is_concrete (); - } + ParamType *handle_substitions (SubstitutionArgumentMappings &mappings); - ParamType *handle_substitions (SubstitutionArgumentMappings mappings); + void set_implicit_self_trait (); + bool is_implicit_self_trait () const; private: + bool is_trait_self; std::string symbol; HIR::GenericParam ¶m; }; @@ -460,31 +310,25 @@ private: class StructFieldType { public: - StructFieldType (HirId ref, std::string name, BaseType *ty, Location locus) - : ref (ref), name (name), ty (ty), locus (locus) - {} + StructFieldType (HirId ref, std::string name, BaseType *ty, Location locus); - HirId get_ref () const { return ref; } - - std::string as_string () const; + HirId get_ref () const; bool is_equal (const StructFieldType &other) const; - std::string get_name () const { return name; } - - BaseType *get_field_type () const { return ty; } + std::string get_name () const; - void set_field_type (BaseType *fty) { ty = fty; } + BaseType *get_field_type () const; + void set_field_type (BaseType *fty); StructFieldType *clone () const; - StructFieldType *monomorphized_clone () const; - bool is_concrete () const { return ty->is_concrete (); } - - void debug () const { rust_debug ("%s", as_string ().c_str ()); } + bool is_concrete () const; - Location get_locus () const { return locus; } + void debug () const; + Location get_locus () const; + std::string as_string () const; private: HirId ref; @@ -498,496 +342,44 @@ class TupleType : public BaseType public: TupleType (HirId ref, Location locus, std::vector<TyVar> fields = std::vector<TyVar> (), - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::TUPLE, - {Resolver::CanonicalPath::create_empty (), locus}, refs), - fields (fields) - {} + std::set<HirId> refs = std::set<HirId> ()); TupleType (HirId ref, HirId ty_ref, Location locus, std::vector<TyVar> fields = std::vector<TyVar> (), - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::TUPLE, - {Resolver::CanonicalPath::create_empty (), locus}, refs), - fields (fields) - {} + std::set<HirId> refs = std::set<HirId> ()); - static TupleType *get_unit_type (HirId ref) - { - return new TupleType (ref, Linemap::predeclared_location ()); - } + static TupleType *get_unit_type (HirId ref); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; - bool is_unit () const override { return this->fields.empty (); } + bool is_unit () const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; - size_t num_fields () const { return fields.size (); } + size_t num_fields () const; BaseType *get_field (size_t index) const; BaseType *clone () const final override; BaseType *monomorphized_clone () const 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; - } + bool is_concrete () const override final; - const std::vector<TyVar> &get_fields () const { return fields; } + const std::vector<TyVar> &get_fields () const; std::string get_name () const override final; - TupleType *handle_substitions (SubstitutionArgumentMappings mappings); + TupleType *handle_substitions (SubstitutionArgumentMappings &mappings); private: std::vector<TyVar> fields; }; -class SubstitutionParamMapping -{ -public: - SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param) - : generic (generic), param (param) - {} - - SubstitutionParamMapping (const SubstitutionParamMapping &other) - : generic (other.generic), param (other.param) - {} - - std::string as_string () const - { - if (param == nullptr) - return "nullptr"; - - return param->get_name (); - } - - bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings, - Location locus); - - SubstitutionParamMapping clone () const - { - return SubstitutionParamMapping (generic, static_cast<ParamType *> ( - param->clone ())); - } - - ParamType *get_param_ty () { return param; } - - const ParamType *get_param_ty () const { return param; } - - const HIR::TypeParam &get_generic_param () { return generic; }; - - // this is used for the backend to override the HirId ref of the param to - // what the concrete type is for the rest of the context - void override_context (); - - bool needs_substitution () const - { - return !(get_param_ty ()->is_concrete ()); - } - - Location get_param_locus () const { return generic.get_locus (); } - - bool param_has_default_ty () const { return generic.has_type (); } - - BaseType *get_default_ty () const - { - TyVar var (generic.get_type_mappings ().get_hirid ()); - return var.get_tyty (); - } - - bool need_substitution () const; - -private: - const HIR::TypeParam &generic; - ParamType *param; -}; - -class SubstitutionArg -{ -public: - SubstitutionArg (const SubstitutionParamMapping *param, BaseType *argument) - : param (param), argument (argument) - {} - - // FIXME - // the copy constructors need removed - they are unsafe see - // TypeBoundPredicate - SubstitutionArg (const SubstitutionArg &other) - : param (other.param), argument (other.argument) - {} - - SubstitutionArg &operator= (const SubstitutionArg &other) - { - param = other.param; - argument = other.argument; - return *this; - } - - BaseType *get_tyty () { return argument; } - - const BaseType *get_tyty () const { return argument; } - - const SubstitutionParamMapping *get_param_mapping () const { return param; } - - static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); } - - bool is_error () const { return param == nullptr || argument == nullptr; } - - bool is_conrete () const - { - if (argument != nullptr) - return true; - - if (argument->get_kind () == TyTy::TypeKind::PARAM) - return false; - - return argument->is_concrete (); - } - - std::string as_string () const - { - return param->as_string () - + (argument != nullptr ? ":" + argument->as_string () : ""); - } - -private: - const SubstitutionParamMapping *param; - BaseType *argument; -}; - -typedef std::function<void (const ParamType &, const SubstitutionArg &)> - ParamSubstCb; -class SubstitutionArgumentMappings -{ -public: - SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings, - Location locus, - ParamSubstCb param_subst_cb = nullptr, - bool trait_item_flag = false) - : mappings (mappings), locus (locus), param_subst_cb (param_subst_cb), - trait_item_flag (trait_item_flag) - {} - - SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other) - : mappings (other.mappings), locus (other.locus), - param_subst_cb (other.param_subst_cb), - trait_item_flag (other.trait_item_flag) - {} - - SubstitutionArgumentMappings & - operator= (const SubstitutionArgumentMappings &other) - { - mappings = other.mappings; - locus = other.locus; - param_subst_cb = other.param_subst_cb; - trait_item_flag = other.trait_item_flag; - - return *this; - } - - SubstitutionArgumentMappings (SubstitutionArgumentMappings &&other) = default; - SubstitutionArgumentMappings &operator= (SubstitutionArgumentMappings &&other) - = default; - - static SubstitutionArgumentMappings error () - { - return SubstitutionArgumentMappings ({}, Location (), nullptr, false); - } - - bool is_error () const { return mappings.size () == 0; } - - bool get_argument_for_symbol (const ParamType *param_to_find, - SubstitutionArg *argument) - { - for (auto &mapping : mappings) - { - const SubstitutionParamMapping *param = mapping.get_param_mapping (); - const ParamType *p = param->get_param_ty (); - - if (p->get_symbol ().compare (param_to_find->get_symbol ()) == 0) - { - *argument = mapping; - return true; - } - } - return false; - } - - bool get_argument_at (size_t index, SubstitutionArg *argument) - { - if (index > mappings.size ()) - return false; - - *argument = mappings.at (index); - return true; - } - - // 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 () const { return locus; } - - size_t size () const { return mappings.size (); } - - bool is_empty () const { return size () == 0; } - - std::vector<SubstitutionArg> &get_mappings () { return mappings; } - - const std::vector<SubstitutionArg> &get_mappings () const { return mappings; } - - std::string as_string () const - { - std::string buffer; - for (auto &mapping : mappings) - { - buffer += mapping.as_string () + ", "; - } - return "<" + buffer + ">"; - } - - void on_param_subst (const ParamType &p, const SubstitutionArg &a) const - { - if (param_subst_cb == nullptr) - return; - - param_subst_cb (p, a); - } - - ParamSubstCb get_subst_cb () const { return param_subst_cb; } - - bool trait_item_mode () const { return trait_item_flag; } - -private: - std::vector<SubstitutionArg> mappings; - Location locus; - ParamSubstCb param_subst_cb; - bool trait_item_flag; -}; - -class SubstitutionRef -{ -public: - SubstitutionRef (std::vector<SubstitutionParamMapping> substitutions, - SubstitutionArgumentMappings arguments) - : substitutions (substitutions), used_arguments (arguments) - {} - - bool has_substitutions () const { return substitutions.size () > 0; } - - std::string subst_as_string () const - { - std::string buffer; - for (size_t i = 0; i < substitutions.size (); i++) - { - const SubstitutionParamMapping &sub = substitutions.at (i); - buffer += sub.as_string (); - - if ((i + 1) < substitutions.size ()) - buffer += ", "; - } - - return buffer.empty () ? "" : "<" + buffer + ">"; - } - - size_t get_num_substitutions () const { return substitutions.size (); } - - std::vector<SubstitutionParamMapping> &get_substs () { return substitutions; } - - const std::vector<SubstitutionParamMapping> &get_substs () const - { - return substitutions; - } - - std::vector<SubstitutionParamMapping> clone_substs () const - { - std::vector<SubstitutionParamMapping> clone; - - for (auto &sub : substitutions) - clone.push_back (sub.clone ()); - - return clone; - } - - void override_context () - { - for (auto &sub : substitutions) - { - sub.override_context (); - } - } - - bool needs_substitution () const - { - for (auto &sub : substitutions) - { - if (sub.need_substitution ()) - return true; - } - return false; - } - - bool was_substituted () const { return !needs_substitution (); } - - SubstitutionArgumentMappings get_substitution_arguments () const - { - return used_arguments; - } - - // this is the count of type params that are not substituted fuly - size_t num_required_substitutions () const - { - size_t n = 0; - for (auto &p : substitutions) - { - if (p.needs_substitution ()) - n++; - } - return n; - } - - // this is the count of type params that need substituted taking into account - // possible defaults - size_t min_required_substitutions () const - { - size_t n = 0; - for (auto &p : substitutions) - { - if (p.needs_substitution () && !p.param_has_default_ty ()) - n++; - } - return n; - } - - // We are trying to subst <i32, f32> into Struct Foo<X,Y> {} - // in the case of Foo<i32,f32>{...} - // - // the substitions we have here define X,Y but the arguments have no bindings - // so its a matter of ordering - SubstitutionArgumentMappings - get_mappings_from_generic_args (HIR::GenericArgs &args); - - // Recursive substitutions - // Foo <A,B> { a:A, b: B}; Bar <X,Y,Z>{a:X, b: Foo<Y,Z>} - // - // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo - // Which binds to A,B - SubstitutionArgumentMappings - adjust_mappings_for_this (SubstitutionArgumentMappings &mappings); - - // Are the mappings here actually bound to this type. For example imagine the - // case: - // - // struct Foo<T>(T); - // impl<T> Foo<T> { - // fn test(self) { ... } - // } - // - // In this case we have a generic ADT of Foo and an impl block of a generic T - // on Foo for the Self type. When we it comes to path resolution we can have: - // - // Foo::<i32>::test() - // - // This means the first segment of Foo::<i32> returns the ADT Foo<i32> not the - // Self ADT bound to the T from the impl block. This means when it comes to - // the next segment of test which resolves to the function we need to check - // wether the arguments in the struct definition of foo can be bound here - // before substituting the previous segments type here. This functions acts as - // a guard for the solve_mappings_from_receiver_for_self to handle the case - // where arguments are not bound. This is important for this next case: - // - // struct Baz<A, B>(A, B); - // impl Baz<i32, f32> { - // fn test<X>(a: X) -> X { - // a - // } - // } - // - // In this case Baz has been already substituted for the impl's Self to become - // ADT<i32, f32> so that the function test only has 1 generic argument of X. - // The path for this will be: - // - // Baz::test::<_>(123) - // - // So the first segment here will be Baz<_, _> to try and infer the arguments - // which will be taken from the impl's Self type in this case since it is - // already substituted and like the previous case the check to see if we need - // to inherit the previous segments generic arguments takes place but the - // generic arguments are not bound to this type as they have already been - // substituted. - // - // Its important to remember from the first example the FnType actually looks - // like: - // - // fn <T>test(self :Foo<T>(T)) - // - // As the generic parameters are "bound" to each of the items in the impl - // block. So this check is about wether the arguments we have here can - // actually be bound to this type. - bool are_mappings_bound (SubstitutionArgumentMappings &mappings); - - // struct Foo<A, B>(A, B); - // - // impl<T> Foo<T, f32>; - // -> fn test<X>(self, a: X) -> X - // - // We might invoke this via: - // - // a = Foo(123, 456f32); - // b = a.test::<bool>(false); - // - // we need to figure out relevant generic arguemts for self to apply to the - // fntype - SubstitutionArgumentMappings solve_mappings_from_receiver_for_self ( - SubstitutionArgumentMappings &mappings) const; - - // TODO comment - SubstitutionArgumentMappings - solve_missing_mappings_from_this (SubstitutionRef &ref, SubstitutionRef &to); - - // TODO comment - BaseType *infer_substitions (Location locus); - - // TODO comment - bool monomorphize (); - - // TODO comment - virtual BaseType *handle_substitions (SubstitutionArgumentMappings mappings) - = 0; - - SubstitutionArgumentMappings get_used_arguments () const - { - return used_arguments; - } - -protected: - std::vector<SubstitutionParamMapping> substitutions; - SubstitutionArgumentMappings used_arguments; -}; - class TypeBoundPredicate : public SubstitutionRef { public: @@ -1030,7 +422,7 @@ public: // WARNING THIS WILL ALWAYS RETURN NULLPTR BaseType * - handle_substitions (SubstitutionArgumentMappings mappings) override final; + handle_substitions (SubstitutionArgumentMappings &mappings) override final; bool is_error () const; @@ -1040,6 +432,13 @@ public: DefId get_id () const { return reference; } + std::vector<TypeBoundPredicateItem> get_associated_type_items (); + + size_t get_num_associated_bindings () const override final; + + TypeBoundPredicateItem + lookup_associated_type (const std::string &search) override final; + private: DefId reference; Location locus; @@ -1057,185 +456,48 @@ public: STRUCT }; - static std::string variant_type_string (VariantType type) - { - switch (type) - { - case NUM: - return "enumeral"; - case TUPLE: - return "tuple"; - case STRUCT: - return "struct"; - } - gcc_unreachable (); - return ""; - } + static std::string variant_type_string (VariantType type); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, - HIR::Expr *discriminant) - : id (id), defid (defid), identifier (identifier), ident (ident), - discriminant (discriminant) - - { - type = VariantType::NUM; - fields = {}; - } + HIR::Expr *discriminant); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, VariantType type, HIR::Expr *discriminant, - std::vector<StructFieldType *> fields) - : id (id), defid (defid), identifier (identifier), ident (ident), - type (type), discriminant (discriminant), fields (fields) - { - rust_assert ( - (type == VariantType::NUM && fields.empty ()) - || (type == VariantType::TUPLE || type == VariantType::STRUCT)); - } - - VariantDef (const VariantDef &other) - : id (other.id), defid (other.defid), identifier (other.identifier), - ident (other.ident), type (other.type), discriminant (other.discriminant), - fields (other.fields) - {} + std::vector<StructFieldType *> fields); - VariantDef &operator= (const VariantDef &other) - { - id = other.id; - identifier = other.identifier; - type = other.type; - discriminant = other.discriminant; - fields = other.fields; - ident = other.ident; - - return *this; - } - - static VariantDef &get_error_node () - { - static VariantDef node - = VariantDef (UNKNOWN_HIRID, UNKNOWN_DEFID, "", - {Resolver::CanonicalPath::create_empty (), - Linemap::unknown_location ()}, - nullptr); + VariantDef (const VariantDef &other); - return node; - } + VariantDef &operator= (const VariantDef &other); - bool is_error () const { return get_id () == UNKNOWN_HIRID; } + static VariantDef &get_error_node (); + bool is_error () const; - HirId get_id () const { return id; } - DefId get_defid () const { return defid; } + HirId get_id () const; + DefId get_defid () const; - VariantType get_variant_type () const { return type; } - bool is_data_variant () const { return type != VariantType::NUM; } - bool is_dataless_variant () const { return type == VariantType::NUM; } + VariantType get_variant_type () const; + bool is_data_variant () const; + bool is_dataless_variant () const; - std::string get_identifier () const { return identifier; } + std::string get_identifier () const; - size_t num_fields () const { return fields.size (); } - StructFieldType *get_field_at_index (size_t index) - { - rust_assert (index < fields.size ()); - return fields.at (index); - } + size_t num_fields () const; + StructFieldType *get_field_at_index (size_t index); - std::vector<StructFieldType *> &get_fields () - { - rust_assert (type != NUM); - return fields; - } + std::vector<StructFieldType *> &get_fields (); bool lookup_field (const std::string &lookup, StructFieldType **field_lookup, - size_t *index) const - { - size_t i = 0; - for (auto &field : fields) - { - if (field->get_name ().compare (lookup) == 0) - { - if (index != nullptr) - *index = i; - - if (field_lookup != nullptr) - *field_lookup = field; - - return true; - } - i++; - } - return false; - } + size_t *index) const; - HIR::Expr *get_discriminant () const - { - rust_assert (discriminant != nullptr); - return discriminant; - } - - std::string as_string () const - { - if (type == VariantType::NUM) - return identifier + " = " + discriminant->as_string (); - - std::string buffer; - for (size_t i = 0; i < fields.size (); ++i) - { - buffer += fields.at (i)->as_string (); - if ((i + 1) < fields.size ()) - buffer += ", "; - } - - if (type == VariantType::TUPLE) - return identifier + " (" + buffer + ")"; - else - return identifier + " {" + buffer + "}"; - } - - bool is_equal (const VariantDef &other) const - { - if (type != other.type) - return false; - - if (identifier.compare (other.identifier) != 0) - return false; - - if (discriminant != other.discriminant) - return false; + HIR::Expr *get_discriminant () const; - if (fields.size () != other.fields.size ()) - return false; - - for (size_t i = 0; i < fields.size (); i++) - { - if (!fields.at (i)->is_equal (*other.fields.at (i))) - return false; - } - - return true; - } - - VariantDef *clone () const - { - std::vector<StructFieldType *> cloned_fields; - for (auto &f : fields) - cloned_fields.push_back ((StructFieldType *) f->clone ()); - - return new VariantDef (id, defid, identifier, ident, type, discriminant, - cloned_fields); - } - - VariantDef *monomorphized_clone () const - { - std::vector<StructFieldType *> cloned_fields; - for (auto &f : fields) - cloned_fields.push_back ((StructFieldType *) f->monomorphized_clone ()); + std::string as_string () const; - return new VariantDef (id, defid, identifier, ident, type, discriminant, - cloned_fields); - } + bool is_equal (const VariantDef &other) const; + VariantDef *clone () const; + VariantDef *monomorphized_clone () const; - const RustIdent &get_ident () const { return ident; } + const RustIdent &get_ident () const; private: HirId id; @@ -1331,7 +593,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1415,7 +676,7 @@ public: } ADTType * - handle_substitions (SubstitutionArgumentMappings mappings) override final; + handle_substitions (SubstitutionArgumentMappings &mappings) override final; private: std::string identifier; @@ -1471,7 +732,6 @@ public: std::string get_identifier () const { return identifier; } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1548,7 +808,7 @@ public: } FnType * - handle_substitions (SubstitutionArgumentMappings mappings) override final; + handle_substitions (SubstitutionArgumentMappings &mappings) override final; ABI get_abi () const { return abi; } @@ -1591,7 +851,6 @@ public: std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1671,7 +930,6 @@ public: std::string as_string () const override; std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1698,7 +956,7 @@ public: } ClosureType * - handle_substitions (SubstitutionArgumentMappings mappings) override final; + handle_substitions (SubstitutionArgumentMappings &mappings) override final; TyTy::TupleType &get_parameters () const { return *parameters; } TyTy::BaseType &get_result_type () const { return *result_type.get_tyty (); } @@ -1740,7 +998,6 @@ public: std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1757,7 +1014,7 @@ public: HIR::Expr &get_capacity_expr () const { return capacity_expr; } - ArrayType *handle_substitions (SubstitutionArgumentMappings mappings); + ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; @@ -1788,7 +1045,6 @@ public: std::string get_name () const override final { return as_string (); } - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -1803,7 +1059,7 @@ public: return get_element_type ()->is_concrete (); } - SliceType *handle_substitions (SubstitutionArgumentMappings mappings); + SliceType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; @@ -1812,33 +1068,21 @@ private: class BoolType : public BaseType { public: - BoolType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::BOOL, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - BoolType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::BOOL, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + BoolType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + BoolType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; }; class IntType : public BaseType @@ -1853,40 +1097,26 @@ public: I128 }; - IntType (HirId ref, IntKind kind, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::INT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - int_kind (kind) - {} - + IntType (HirId ref, IntKind kind, std::set<HirId> refs = std::set<HirId> ()); IntType (HirId ref, HirId ty_ref, IntKind kind, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::INT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - int_kind (kind) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; - IntKind get_int_kind () const { return int_kind; } + IntKind get_int_kind () const; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; bool is_equal (const BaseType &other) const override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; private: IntKind int_kind; @@ -1904,40 +1134,27 @@ public: U128 }; - UintType (HirId ref, UintKind kind, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::UINT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - uint_kind (kind) - {} - + UintType (HirId ref, UintKind kind, + std::set<HirId> refs = std::set<HirId> ()); UintType (HirId ref, HirId ty_ref, UintKind kind, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::UINT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - uint_kind (kind) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; - UintKind get_uint_kind () const { return uint_kind; } + UintKind get_uint_kind () const; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; bool is_equal (const BaseType &other) const override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; private: UintKind uint_kind; @@ -1953,40 +1170,25 @@ public: }; FloatType (HirId ref, FloatKind kind, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::FLOAT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - float_kind (kind) - {} - + std::set<HirId> refs = std::set<HirId> ()); FloatType (HirId ref, HirId ty_ref, FloatKind kind, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::FLOAT, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - float_kind (kind) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; + std::string get_name () const override final; - std::string get_name () const override final { return as_string (); } - - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; - FloatKind get_float_kind () const { return float_kind; } + FloatKind get_float_kind () const; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; bool is_equal (const BaseType &other) const override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; private: FloatKind float_kind; @@ -1995,153 +1197,91 @@ private: class USizeType : public BaseType { public: - USizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::USIZE, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - USizeType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::USIZE, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + USizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + USizeType (HirId ref, HirId ty_ref, + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; + std::string get_name () const override final; - std::string get_name () const override final { return as_string (); } - - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; }; class ISizeType : public BaseType { public: - ISizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::ISIZE, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - ISizeType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::ISIZE, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + ISizeType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + ISizeType (HirId ref, HirId ty_ref, + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; + std::string get_name () const override final; - std::string get_name () const override final { return as_string (); } - - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; }; class CharType : public BaseType { public: - CharType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::CHAR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - CharType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::CHAR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + CharType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + CharType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; + std::string get_name () const override final; - std::string get_name () const override final { return as_string (); } - - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; }; class StrType : public BaseType { public: - StrType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::STR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::STR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + StrType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()); - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; }; class ReferenceType : public BaseType { public: ReferenceType (HirId ref, TyVar base, Mutability mut, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::REF, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - base (base), mut (mut) - {} - + std::set<HirId> refs = std::set<HirId> ()); ReferenceType (HirId ref, HirId ty_ref, TyVar base, Mutability mut, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::REF, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - base (base), mut (mut) - {} + std::set<HirId> refs = std::set<HirId> ()); BaseType *get_base () const; @@ -2152,7 +1292,6 @@ public: std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -2160,45 +1299,19 @@ public: BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final - { - return get_base ()->is_concrete (); - } - - ReferenceType *handle_substitions (SubstitutionArgumentMappings mappings); + bool is_concrete () const override final; - Mutability mutability () const { return mut; } + ReferenceType *handle_substitions (SubstitutionArgumentMappings &mappings); - bool is_mutable () const { return mut == Mutability::Mut; } + Mutability mutability () const; - bool is_dyn_object () const - { - return is_dyn_slice_type () || is_dyn_str_type (); - } + bool is_mutable () const; - bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const - { - const TyTy::BaseType *element = get_base ()->destructure (); - if (element->get_kind () != TyTy::TypeKind::SLICE) - return false; - if (slice == nullptr) - return true; + bool is_dyn_object () const; - *slice = static_cast<const TyTy::SliceType *> (element); - return true; - } + bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; - bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const - { - const TyTy::BaseType *element = get_base ()->destructure (); - if (element->get_kind () != TyTy::TypeKind::STR) - return false; - if (str == nullptr) - return true; - - *str = static_cast<const TyTy::StrType *> (element); - return true; - } + bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; private: TyVar base; @@ -2209,22 +1322,9 @@ class PointerType : public BaseType { public: PointerType (HirId ref, TyVar base, Mutability mut, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::POINTER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - base (base), mut (mut) - {} - + std::set<HirId> refs = std::set<HirId> ()); PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::POINTER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - base (base), mut (mut) - {} + std::set<HirId> refs = std::set<HirId> ()); BaseType *get_base () const; @@ -2234,7 +1334,6 @@ public: std::string as_string () const override; std::string get_name () const override final; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -2242,47 +1341,17 @@ public: BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final - { - return get_base ()->is_concrete (); - } - - PointerType *handle_substitions (SubstitutionArgumentMappings mappings); - - Mutability mutability () const { return mut; } - - bool is_mutable () const { return mut == Mutability::Mut; } - - bool is_const () const { return mut == Mutability::Imm; } - - bool is_dyn_object () const - { - return is_dyn_slice_type () || is_dyn_str_type (); - } - - bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const - { - const TyTy::BaseType *element = get_base ()->destructure (); - if (element->get_kind () != TyTy::TypeKind::SLICE) - return false; - if (slice == nullptr) - return true; + bool is_concrete () const override final; - *slice = static_cast<const TyTy::SliceType *> (element); - return true; - } + PointerType *handle_substitions (SubstitutionArgumentMappings &mappings); - bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const - { - const TyTy::BaseType *element = get_base ()->destructure (); - if (element->get_kind () != TyTy::TypeKind::STR) - return false; - if (str == nullptr) - return true; + Mutability mutability () const; + bool is_mutable () const; + bool is_const () const; + bool is_dyn_object () const; - *str = static_cast<const TyTy::StrType *> (element); - return true; - } + bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; + bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; private: TyVar base; @@ -2302,35 +1371,24 @@ private: class NeverType : public BaseType { public: - NeverType (HirId ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::NEVER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - NeverType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::NEVER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} + NeverType (HirId ref, std::set<HirId> refs = std::set<HirId> ()); + NeverType (HirId ref, HirId ty_ref, + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - bool is_unit () const override { return true; } - bool is_concrete () const override final { return true; } + bool is_unit () const override; + bool is_concrete () const override final; }; // used at the type in associated types in traits @@ -2339,43 +1397,25 @@ class PlaceholderType : public BaseType { public: PlaceholderType (std::string symbol, HirId ref, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::PLACEHOLDER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - symbol (symbol) - {} - + std::set<HirId> refs = std::set<HirId> ()); PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::PLACEHOLDER, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - symbol (symbol) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - bool is_unit () const override - { - rust_assert (can_resolve ()); - return resolve ()->is_unit (); - } + bool is_unit () const override; - std::string get_symbol () const { return symbol; } + std::string get_symbol () const; void set_associated_type (HirId ref); @@ -2387,13 +1427,7 @@ public: bool is_equal (const BaseType &other) const override; - bool is_concrete () const override final - { - if (!can_resolve ()) - return true; - - return resolve ()->is_concrete (); - } + bool is_concrete () const override final; private: std::string symbol; @@ -2407,63 +1441,42 @@ public: std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::PROJECTION, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)), - base (base), trait (trait), item (item) - {} + std::set<HirId> refs = std::set<HirId> ()); ProjectionType (HirId ref, HirId ty_ref, BaseType *base, const Resolver::TraitReference *trait, DefId item, std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::PROJECTION, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs), - SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)), - base (base), trait (trait), item (item) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; - std::string get_name () const override final { return as_string (); } + std::string get_name () const override final; - bool is_unit () const override { return false; } + bool is_unit () const override; - bool needs_generic_substitutions () const override final - { - return needs_substitution (); - } + bool needs_generic_substitutions () const override final; - bool supports_substitutions () const override final { return true; } + bool supports_substitutions () const override final; - bool has_subsititions_defined () const override final - { - return has_substitutions (); - } + bool has_subsititions_defined () const override final; - const BaseType *get () const { return base; } - BaseType *get () { return base; } + const BaseType *get () const; + BaseType *get (); - bool is_concrete () const override final { return base->is_concrete (); } + bool is_concrete () const override final; ProjectionType * - handle_substitions (SubstitutionArgumentMappings mappings) override final; + handle_substitions (SubstitutionArgumentMappings &mappings) override final; private: BaseType *base; @@ -2476,22 +1489,17 @@ class DynamicObjectType : public BaseType public: DynamicObjectType (HirId ref, RustIdent ident, std::vector<TypeBoundPredicate> specified_bounds, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::DYNAMIC, ident, specified_bounds, refs) - {} + std::set<HirId> refs = std::set<HirId> ()); DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident, std::vector<TypeBoundPredicate> specified_bounds, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::DYNAMIC, ident, specified_bounds, refs) - {} + std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; - BaseType *unify (BaseType *other) override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; @@ -2501,7 +1509,7 @@ public: std::string get_name () const override final; - bool is_concrete () const override final { return true; } + bool is_concrete () const override final; // this returns a flat list of items including super trait bounds const std::vector< diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc new file mode 100644 index 0000000..cbbff8c --- /dev/null +++ b/gcc/rust/typecheck/rust-unify.cc @@ -0,0 +1,1651 @@ +// Copyright (C) 2020-2023 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/>. + +#include "rust-unify.h" + +namespace Rust { +namespace Resolver { + +UnifyRules::UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location locus, bool commit_flag, bool emit_error) + : lhs (lhs), rhs (rhs), locus (locus), commit_flag (commit_flag), + emit_error (emit_error), mappings (*Analysis::Mappings::get ()), + context (*TypeCheckContext::get ()) +{} + +TyTy::BaseType * +UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location locus, bool commit_flag, bool emit_error) +{ + UnifyRules r (lhs, rhs, locus, commit_flag, emit_error); + TyTy::BaseType *result = r.go (); + + if (r.commit_flag) + r.commit (result); + + bool failed = result->get_kind () == TyTy::TypeKind::ERROR; + if (failed && r.emit_error) + r.emit_type_mismatch (); + + return result; +} + +TyTy::BaseType * +UnifyRules::get_base () +{ + return lhs.get_ty ()->destructure (); +} + +TyTy::BaseType * +UnifyRules::get_other () +{ + return rhs.get_ty ()->destructure (); +} + +void +UnifyRules::commit (TyTy::BaseType *resolved) +{ + resolved->append_reference (get_base ()->get_ref ()); + resolved->append_reference (get_other ()->get_ref ()); + for (auto ref : get_base ()->get_combined_refs ()) + resolved->append_reference (ref); + for (auto ref : get_other ()->get_combined_refs ()) + resolved->append_reference (ref); + + get_other ()->append_reference (resolved->get_ref ()); + get_other ()->append_reference (get_base ()->get_ref ()); + get_base ()->append_reference (resolved->get_ref ()); + get_base ()->append_reference (get_other ()->get_ref ()); + + bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER; + bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER; + bool results_is_non_general_infer_var + = (result_is_infer_var + && (static_cast<TyTy::InferType *> (resolved))->get_infer_kind () + != TyTy::InferType::GENERAL); + if (result_resolved || results_is_non_general_infer_var) + { + for (auto &ref : resolved->get_combined_refs ()) + { + TyTy::BaseType *ref_tyty = nullptr; + bool ok = context.lookup_type (ref, &ref_tyty); + if (!ok) + continue; + + // if any of the types are inference variables lets fix them + if (ref_tyty->get_kind () == TyTy::TypeKind::INFER) + { + auto node = Analysis::NodeMapping (mappings.get_current_crate (), + UNKNOWN_NODEID, ref, + UNKNOWN_LOCAL_DEFID); + context.insert_type (node, resolved->clone ()); + } + } + } +} + +void +UnifyRules::emit_type_mismatch () const +{ + TyTy::BaseType *expected = lhs.get_ty (); + TyTy::BaseType *expr = rhs.get_ty (); + + RichLocation r (locus); + r.add_range (lhs.get_locus ()); + r.add_range (rhs.get_locus ()); + rust_error_at (r, "expected %<%s%> got %<%s%>", + expected->get_name ().c_str (), expr->get_name ().c_str ()); +} + +TyTy::BaseType * +UnifyRules::go () +{ + TyTy::BaseType *ltype = lhs.get_ty (); + TyTy::BaseType *rtype = rhs.get_ty (); + + ltype = lhs.get_ty ()->destructure (); + rtype = rhs.get_ty ()->destructure (); + + rust_debug ("unify::go ltype={%s} rtype={%s}", ltype->debug_str ().c_str (), + rtype->debug_str ().c_str ()); + + // check bounds + if (ltype->num_specified_bounds () > 0) + { + if (!ltype->bounds_compatible (*rtype, locus, true)) + { + // already emitted an error + emit_error = false; + return new TyTy::ErrorType (0); + } + } + + switch (ltype->get_kind ()) + { + case TyTy::INFER: + return expect_inference_variable (static_cast<TyTy::InferType *> (ltype), + rtype); + + case TyTy::ADT: + return expect_adt (static_cast<TyTy::ADTType *> (ltype), rtype); + + case TyTy::STR: + return expect_str (static_cast<TyTy::StrType *> (ltype), rtype); + + case TyTy::REF: + return expect_reference (static_cast<TyTy::ReferenceType *> (ltype), + rtype); + + case TyTy::POINTER: + return expect_pointer (static_cast<TyTy::PointerType *> (ltype), rtype); + + case TyTy::PARAM: + return expect_param (static_cast<TyTy::ParamType *> (ltype), rtype); + + case TyTy::ARRAY: + return expect_array (static_cast<TyTy::ArrayType *> (ltype), rtype); + + case TyTy::SLICE: + return expect_slice (static_cast<TyTy::SliceType *> (ltype), rtype); + + case TyTy::FNDEF: + return expect_fndef (static_cast<TyTy::FnType *> (ltype), rtype); + + case TyTy::FNPTR: + return expect_fnptr (static_cast<TyTy::FnPtr *> (ltype), rtype); + + case TyTy::TUPLE: + return expect_tuple (static_cast<TyTy::TupleType *> (ltype), rtype); + + case TyTy::BOOL: + return expect_bool (static_cast<TyTy::BoolType *> (ltype), rtype); + + case TyTy::CHAR: + return expect_char (static_cast<TyTy::CharType *> (ltype), rtype); + + case TyTy::INT: + return expect_int (static_cast<TyTy::IntType *> (ltype), rtype); + + case TyTy::UINT: + return expect_uint (static_cast<TyTy::UintType *> (ltype), rtype); + + case TyTy::FLOAT: + return expect_float (static_cast<TyTy::FloatType *> (ltype), rtype); + + case TyTy::USIZE: + return expect_usize (static_cast<TyTy::USizeType *> (ltype), rtype); + + case TyTy::ISIZE: + return expect_isize (static_cast<TyTy::ISizeType *> (ltype), rtype); + + case TyTy::NEVER: + return expect_never (static_cast<TyTy::NeverType *> (ltype), rtype); + + case TyTy::PLACEHOLDER: + return expect_placeholder (static_cast<TyTy::PlaceholderType *> (ltype), + rtype); + + case TyTy::PROJECTION: + return expect_projection (static_cast<TyTy::ProjectionType *> (ltype), + rtype); + + case TyTy::DYNAMIC: + return expect_dyn (static_cast<TyTy::DynamicObjectType *> (ltype), rtype); + + case TyTy::CLOSURE: + return expect_closure (static_cast<TyTy::ClosureType *> (ltype), rtype); + + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_inference_variable (TyTy::InferType *ltype, + TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + switch (ltype->get_infer_kind ()) + { + case TyTy::InferType::InferTypeKind::GENERAL: + return rtype->clone (); + + case TyTy::InferType::InferTypeKind::INTEGRAL: { + bool is_valid = r->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL + || r->get_infer_kind () + == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return rtype->clone (); + } + break; + + case TyTy::InferType::InferTypeKind::FLOAT: { + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT + || r->get_infer_kind () + == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return rtype->clone (); + } + break; + } + } + break; + + case TyTy::INT: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::ISIZE: { + bool is_valid = (ltype->get_infer_kind () + == TyTy::InferType::InferTypeKind::GENERAL) + || (ltype->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL); + if (is_valid) + return rtype->clone (); + } + break; + + case TyTy::FLOAT: { + bool is_valid = (ltype->get_infer_kind () + == TyTy::InferType::InferTypeKind::GENERAL) + || (ltype->get_infer_kind () + == TyTy::InferType::InferTypeKind::FLOAT); + if (is_valid) + return rtype->clone (); + } + break; + + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: { + bool is_valid = (ltype->get_infer_kind () + == TyTy::InferType::InferTypeKind::GENERAL); + if (is_valid) + return rtype->clone (); + } + break; + + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::ADT: { + TyTy::ADTType &type = *static_cast<TyTy::ADTType *> (rtype); + if (ltype->get_adt_kind () != type.get_adt_kind ()) + { + return new TyTy::ErrorType (0); + } + + if (ltype->get_identifier ().compare (type.get_identifier ()) != 0) + { + return new TyTy::ErrorType (0); + } + + if (ltype->number_of_variants () != type.number_of_variants ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < type.number_of_variants (); ++i) + { + TyTy::VariantDef *a = ltype->get_variants ().at (i); + TyTy::VariantDef *b = type.get_variants ().at (i); + + if (a->num_fields () != b->num_fields ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t j = 0; j < a->num_fields (); j++) + { + TyTy::StructFieldType *base_field = a->get_field_at_index (j); + TyTy::StructFieldType *other_field = b->get_field_at_index (j); + + TyTy::BaseType *this_field_ty = base_field->get_field_type (); + TyTy::BaseType *other_field_ty = other_field->get_field_type (); + + TyTy::BaseType *unified_ty + = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty), + TyTy::TyWithLocation (other_field_ty), + locus, commit_flag, + false /* emit_error */); + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + } + + // generic args for the unit-struct case + if (type.is_unit () && ltype->is_unit ()) + { + rust_assert (type.get_num_substitutions () + == ltype->get_num_substitutions ()); + + for (size_t i = 0; i < type.get_num_substitutions (); i++) + { + auto &a = ltype->get_substs ().at (i); + auto &b = type.get_substs ().at (i); + + auto pa = a.get_param_ty (); + auto pb = b.get_param_ty (); + + auto res + = UnifyRules::Resolve (TyTy::TyWithLocation (pa), + TyTy::TyWithLocation (pb), locus, + commit_flag, false /* emit_error */); + if (res->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + } + + return type.clone (); + } + break; + + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::STR: + return rtype->clone (); + + case TyTy::ADT: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::REF: { + TyTy::ReferenceType &type = *static_cast<TyTy::ReferenceType *> (rtype); + auto base_type = ltype->get_base (); + auto other_base_type = type.get_base (); + + TyTy::BaseType *base_resolved + = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type), locus, + commit_flag, false /* emit_error */); + if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + // rust is permissive about mutablity here you can always go from + // mutable to immutable but not the otherway round + bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true; + if (!mutability_ok) + { + return new TyTy::ErrorType (0); + } + + return new TyTy::ReferenceType (ltype->get_ref (), ltype->get_ty_ref (), + TyTy::TyVar (base_resolved->get_ref ()), + ltype->mutability ()); + } + break; + + case TyTy::STR: + case TyTy::ADT: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::POINTER: { + TyTy::PointerType &type = *static_cast<TyTy::PointerType *> (rtype); + auto base_type = ltype->get_base (); + auto other_base_type = type.get_base (); + + TyTy::BaseType *base_resolved + = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type), locus, + commit_flag, false /* emit_error */); + if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + // rust is permissive about mutablity here you can always go from + // mutable to immutable but not the otherway round + bool mutability_ok = ltype->is_mutable () ? type.is_mutable () : true; + if (!mutability_ok) + { + return new TyTy::ErrorType (0); + } + + return new TyTy::PointerType (ltype->get_ref (), ltype->get_ty_ref (), + TyTy::TyVar (base_resolved->get_ref ()), + ltype->mutability ()); + } + break; + + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::PARAM: { + TyTy::ParamType &type = *static_cast<TyTy::ParamType *> (rtype); + // bool symbol_matches + // = ltype->get_symbol ().compare (type.get_symbol ()) == 0; + // // TODO + // // I think rustc checks a debruinj index + // if (symbol_matches) + // { + // return type.clone (); + // } + + // matching symbol is not going to work when we mix symbol's and have + // nested generics + + // bounds match? FIXME + + return type.clone (); + } + break; + + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::ARRAY: { + TyTy::ArrayType &type = *static_cast<TyTy::ArrayType *> (rtype); + TyTy::BaseType *element_unify = UnifyRules::Resolve ( + TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, + false /* emit_error*/); + + if (element_unify->get_kind () != TyTy::TypeKind::ERROR) + { + return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, + type.get_capacity_expr (), + TyTy::TyVar ( + element_unify->get_ref ())); + } + } + break; + + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::SLICE: { + TyTy::SliceType &type = *static_cast<TyTy::SliceType *> (rtype); + TyTy::BaseType *element_unify = UnifyRules::Resolve ( + TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, + false /* emit_error*/); + + if (element_unify->get_kind () != TyTy::TypeKind::ERROR) + { + return new TyTy::SliceType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, + TyTy::TyVar ( + element_unify->get_ref ())); + } + } + break; + + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::FNDEF: { + TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype); + if (ltype->num_params () != type.num_params ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < ltype->num_params (); i++) + { + auto a = ltype->param_at (i).second; + auto b = type.param_at (i).second; + + auto unified_param + = UnifyRules::Resolve (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b), locus, + commit_flag, false /* emit_errors */); + if (unified_param->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + + auto unified_return + = UnifyRules::Resolve (TyTy::TyWithLocation ( + ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ()), + locus, commit_flag, false /* emit_errors */); + if (unified_return->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + return ltype->clone (); + } + break; + + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNPTR: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::FNPTR: { + TyTy::FnPtr &type = *static_cast<TyTy::FnPtr *> (rtype); + if (ltype->num_params () != type.num_params ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < ltype->num_params (); i++) + { + auto a = ltype->param_at (i); + auto b = type.param_at (i); + + auto unified_param + = UnifyRules::Resolve (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b), locus, + commit_flag, false /* emit_errors */); + if (unified_param->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + + auto unified_return + = UnifyRules::Resolve (TyTy::TyWithLocation ( + ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ()), + locus, commit_flag, false /* emit_errors */); + if (unified_return->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + return ltype->clone (); + } + break; + + case TyTy::FNDEF: { + TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype); + auto this_ret_type = ltype->get_return_type (); + auto other_ret_type = type.get_return_type (); + + auto unified_result + = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type), + TyTy::TyWithLocation (other_ret_type), locus, + commit_flag, false /*emit_errors*/); + if (unified_result->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + if (ltype->num_params () != type.num_params ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < ltype->num_params (); i++) + { + auto this_param = ltype->param_at (i); + auto other_param = type.param_at (i).second; + + auto unified_param + = UnifyRules::Resolve (TyTy::TyWithLocation (this_param), + TyTy::TyWithLocation (other_param), locus, + commit_flag, false /* emit_errors */); + if (unified_param->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + + return ltype->clone (); + } + break; + + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::TUPLE: { + TyTy::TupleType &type = *static_cast<TyTy::TupleType *> (rtype); + if (ltype->num_fields () != type.num_fields ()) + { + return new TyTy::ErrorType (0); + } + + std::vector<TyTy::TyVar> fields; + for (size_t i = 0; i < ltype->num_fields (); i++) + { + TyTy::BaseType *bo = ltype->get_field (i); + TyTy::BaseType *fo = type.get_field (i); + + TyTy::BaseType *unified_ty + = UnifyRules::Resolve (TyTy::TyWithLocation (bo), + TyTy::TyWithLocation (fo), locus, + commit_flag, false /* emit_errors */); + if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + + fields.push_back (TyTy::TyVar (unified_ty->get_ref ())); + } + + return new TyTy::TupleType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, fields); + } + break; + + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::BOOL: + return rtype->clone (); + + case TyTy::CHAR: + case TyTy::INT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::CHAR: + return rtype->clone (); + + case TyTy::INT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL + || r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::INT: { + TyTy::IntType &type = *static_cast<TyTy::IntType *> (rtype); + bool is_valid = ltype->get_int_kind () == type.get_int_kind (); + if (is_valid) + return new TyTy::IntType (type.get_ref (), type.get_ty_ref (), + type.get_int_kind ()); + } + break; + + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL + || r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::UINT: { + TyTy::UintType &type = *static_cast<TyTy::UintType *> (rtype); + bool is_valid = ltype->get_uint_kind () == type.get_uint_kind (); + if (is_valid) + return new TyTy::UintType (type.get_ref (), type.get_ty_ref (), + type.get_uint_kind ()); + } + break; + + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL + || r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::FLOAT: { + TyTy::FloatType &type = *static_cast<TyTy::FloatType *> (rtype); + bool is_valid = ltype->get_float_kind () == type.get_float_kind (); + if (is_valid) + return new TyTy::FloatType (type.get_ref (), type.get_ty_ref (), + type.get_float_kind ()); + } + break; + + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::ISIZE: + return rtype->clone (); + + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::USIZE: + return rtype->clone (); + + case TyTy::ADT: + case TyTy::STR: + case TyTy::REF: + case TyTy::POINTER: + case TyTy::PARAM: + case TyTy::ARRAY: + case TyTy::SLICE: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::NEVER: + return rtype->clone (); + + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype, + TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::PLACEHOLDER: { + TyTy::PlaceholderType &type + = *static_cast<TyTy::PlaceholderType *> (rtype); + bool symbol_match + = ltype->get_symbol ().compare (type.get_symbol ()) == 0; + if (symbol_match) + { + return type.clone (); + } + } + break; + + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_projection (TyTy::ProjectionType *ltype, + TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + // FIXME + case TyTy::PROJECTION: + gcc_unreachable (); + break; + + case TyTy::DYNAMIC: + case TyTy::CLOSURE: + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::DYNAMIC: { + TyTy::DynamicObjectType &type + = *static_cast<TyTy::DynamicObjectType *> (rtype); + if (ltype->num_specified_bounds () != type.num_specified_bounds ()) + { + return new TyTy::ErrorType (0); + } + + if (!ltype->bounds_compatible (type, locus, true)) + { + return new TyTy::ErrorType (0); + } + + return ltype->clone (); + } + break; + + case TyTy::CLOSURE: + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::CLOSURE: { + TyTy::ClosureType &type = *static_cast<TyTy::ClosureType *> (rtype); + if (ltype->get_def_id () != type.get_def_id ()) + { + return new TyTy::ErrorType (0); + } + + TyTy::BaseType *args_res + = UnifyRules::Resolve (TyTy::TyWithLocation ( + <ype->get_parameters ()), + TyTy::TyWithLocation (&type.get_parameters ()), + locus, commit_flag, false /* emit_error */); + if (args_res->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + TyTy::BaseType *res = UnifyRules::Resolve ( + TyTy::TyWithLocation (<ype->get_result_type ()), + TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag, + false /* emit_error */); + if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + return ltype->clone (); + } + break; + + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h new file mode 100644 index 0000000..75fb884 --- /dev/null +++ b/gcc/rust/typecheck/rust-unify.h @@ -0,0 +1,91 @@ +// Copyright (C) 2020-2023 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_UNIFY +#define RUST_UNIFY + +#include "rust-tyty-util.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Resolver { + +class UnifyRules +{ +public: + static TyTy::BaseType *Resolve (TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, Location locus, + bool commit_flag, bool emit_error); + +protected: + TyTy::BaseType *expect_inference_variable (TyTy::InferType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_reference (TyTy::ReferenceType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_pointer (TyTy::PointerType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_placeholder (TyTy::PlaceholderType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_projection (TyTy::ProjectionType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_dyn (TyTy::DynamicObjectType *ltype, + TyTy::BaseType *rtype); + TyTy::BaseType *expect_closure (TyTy::ClosureType *ltype, + TyTy::BaseType *rtype); + +private: + UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location locus, bool commit_flag, bool emit_error); + + void emit_type_mismatch () const; + void commit (TyTy::BaseType *resolved); + TyTy::BaseType *go (); + + TyTy::BaseType *get_base (); + TyTy::BaseType *get_other (); + + TyTy::TyWithLocation lhs; + TyTy::TyWithLocation rhs; + Location locus; + bool commit_flag; + bool emit_error; + + Analysis::Mappings &mappings; + TypeCheckContext &context; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_UNIFY diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index 33f2c93..4f63dd0 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -41,6 +41,9 @@ static const BuiltinAttrDefinition __definitions[] {"repr", CODE_GENERATION}, {"path", EXPANSION}, {"macro_use", NAME_RESOLUTION}, + // FIXME: This is not implemented yet, see + // https://github.com/Rust-GCC/gccrs/issues/1475 + {"target_feature", CODE_GENERATION}, // From now on, these are reserved by the compiler and gated through // #![feature(rustc_attrs)] {"rustc_inherit_overflow_checks", CODE_GENERATION}}; @@ -764,6 +767,10 @@ void AttributeChecker::visit (AST::SlicePattern &) {} +void +AttributeChecker::visit (AST::AltPattern &) +{} + // rust-stmt.h void AttributeChecker::visit (AST::EmptyStmt &) diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index c08378c..805e3a8 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -242,6 +242,7 @@ private: void visit (AST::TuplePattern &pattern); void visit (AST::GroupedPattern &pattern); void visit (AST::SlicePattern &pattern); + void visit (AST::AltPattern &pattern); // rust-stmt.h void visit (AST::EmptyStmt &stmt); diff --git a/gcc/rust/rust-buffered-queue.h b/gcc/rust/util/rust-buffered-queue.h index 20dd768..20dd768 100644 --- a/gcc/rust/rust-buffered-queue.h +++ b/gcc/rust/util/rust-buffered-queue.h diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 1fc3203..a968704 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -96,9 +96,16 @@ static const HirId kDefaultCrateNumBegin = 0; Mappings::Mappings () : crateNumItr (kDefaultCrateNumBegin), currentCrateNum (UNKNOWN_CREATENUM), hirIdIter (kDefaultHirIdBegin), nodeIdIter (kDefaultNodeIdBegin) -{} +{ + Analysis::NodeMapping node (0, 0, 0, 0); + builtinMarker + = new HIR::ImplBlock (node, {}, {}, nullptr, nullptr, HIR::WhereClause ({}), + Positive, + HIR::Visibility (HIR::Visibility::VisType::PUBLIC), + {}, {}, Location ()); +} -Mappings::~Mappings () {} +Mappings::~Mappings () { delete builtinMarker; } Mappings * Mappings::get () @@ -1035,5 +1042,11 @@ Mappings::lookup_ast_item (NodeId id, AST::Item **result) return true; } +HIR::ImplBlock * +Mappings::lookup_builtin_marker () +{ + return builtinMarker; +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 13cae71..9d6affa 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -296,6 +296,8 @@ public: void insert_ast_item (AST::Item *item); bool lookup_ast_item (NodeId id, AST::Item **result); + HIR::ImplBlock *lookup_builtin_marker (); + private: Mappings (); @@ -304,6 +306,7 @@ private: HirId hirIdIter; NodeId nodeIdIter; std::map<CrateNum, LocalDefId> localIdIter; + HIR::ImplBlock *builtinMarker; std::map<NodeId, CrateNum> crate_node_to_crate_num; std::map<CrateNum, AST::Crate *> ast_crate_mappings; diff --git a/gcc/rust/util/rust-inline-visitor.h b/gcc/rust/util/rust-inline-visitor.h index 105a67b..9240627 100644 --- a/gcc/rust/util/rust-inline-visitor.h +++ b/gcc/rust/util/rust-inline-visitor.h @@ -1,4 +1,4 @@ -// Copyright (C) 2021-2022 Free Software Foundation, Inc. +// Copyright (C) 2021-2023 Free Software Foundation, Inc. // This file is part of GCC. diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h index ea0c91a..c5ef620 100644 --- a/gcc/rust/util/rust-lang-item.h +++ b/gcc/rust/util/rust-lang-item.h @@ -17,7 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-system.h" -#include "operator.h" +#include "rust-operators.h" namespace Rust { namespace Analysis { @@ -80,6 +80,12 @@ public: FN_ONCE, FN_ONCE_OUTPUT, + // markers + COPY, + CLONE, + SIZED, + + // delimiter UNKNOWN, }; @@ -237,6 +243,18 @@ public: { return ItemType::FN_ONCE_OUTPUT; } + else if (item.compare ("copy") == 0) + { + return ItemType::COPY; + } + else if (item.compare ("clone") == 0) + { + return ItemType::CLONE; + } + else if (item.compare ("sized") == 0) + { + return ItemType::SIZED; + } return ItemType::UNKNOWN; } @@ -321,6 +339,12 @@ public: return "fn_once"; case FN_ONCE_OUTPUT: return "fn_once_output"; + case COPY: + return "copy"; + case CLONE: + return "clone"; + case SIZED: + return "sized"; case UNKNOWN: return "<UNKNOWN>"; diff --git a/gcc/rust/operator.h b/gcc/rust/util/rust-operators.h index dab44e9..dab44e9 100644 --- a/gcc/rust/operator.h +++ b/gcc/rust/util/rust-operators.h |