| // 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-type.h" |
| #include "rust-hir-trait-resolve.h" |
| #include "rust-hir-type-check-expr.h" |
| |
| namespace Rust { |
| namespace Resolver { |
| |
| HIR::GenericArgs |
| TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment) |
| { |
| TypeCheckResolveGenericArguments resolver (segment->get_locus ()); |
| switch (segment->get_type ()) |
| { |
| case HIR::TypePathSegment::SegmentType::GENERIC: |
| resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment)); |
| break; |
| |
| default: |
| break; |
| } |
| return resolver.args; |
| } |
| |
| void |
| TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic) |
| { |
| args = generic.get_generic_args (); |
| } |
| |
| TyTy::BaseType * |
| TypeCheckType::Resolve (HIR::Type *type) |
| { |
| // is it already resolved? |
| auto context = TypeCheckContext::get (); |
| TyTy::BaseType *resolved = nullptr; |
| bool already_resolved |
| = context->lookup_type (type->get_mappings ().get_hirid (), &resolved); |
| if (already_resolved) |
| return resolved; |
| |
| TypeCheckType resolver (type->get_mappings ().get_hirid ()); |
| type->accept_vis (resolver); |
| rust_assert (resolver.translated != nullptr); |
| resolver.context->insert_type (type->get_mappings (), resolver.translated); |
| return resolver.translated; |
| } |
| |
| void |
| TypeCheckType::visit (HIR::BareFunctionType &fntype) |
| { |
| TyTy::BaseType *return_type |
| = fntype.has_return_type () |
| ? TypeCheckType::Resolve (fntype.get_return_type ().get ()) |
| : TyTy::TupleType::get_unit_type (fntype.get_mappings ().get_hirid ()); |
| |
| std::vector<TyTy::TyVar> params; |
| for (auto ¶m : fntype.get_function_params ()) |
| { |
| TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ().get ()); |
| params.push_back (TyTy::TyVar (ptype->get_ref ())); |
| } |
| |
| translated = new TyTy::FnPtr (fntype.get_mappings ().get_hirid (), |
| fntype.get_locus (), std::move (params), |
| TyTy::TyVar (return_type->get_ref ())); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::TupleType &tuple) |
| { |
| if (tuple.is_unit_type ()) |
| { |
| auto unit_node_id = resolver->get_unit_type_node_id (); |
| if (!context->lookup_builtin (unit_node_id, &translated)) |
| { |
| rust_error_at (tuple.get_locus (), |
| "failed to lookup builtin unit type"); |
| } |
| return; |
| } |
| |
| std::vector<TyTy::TyVar> fields; |
| for (auto &elem : tuple.get_elems ()) |
| { |
| auto field_ty = TypeCheckType::Resolve (elem.get ()); |
| fields.push_back (TyTy::TyVar (field_ty->get_ref ())); |
| } |
| |
| translated = new TyTy::TupleType (tuple.get_mappings ().get_hirid (), |
| tuple.get_locus (), fields); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::TypePath &path) |
| { |
| // this can happen so we need to look up the root then resolve the |
| // remaining segments if possible |
| size_t offset = 0; |
| NodeId resolved_node_id = UNKNOWN_NODEID; |
| TyTy::BaseType *root = resolve_root_path (path, &offset, &resolved_node_id); |
| if (root->get_kind () == TyTy::TypeKind::ERROR) |
| return; |
| |
| TyTy::BaseType *path_type = root->clone (); |
| path_type->set_ref (path.get_mappings ().get_hirid ()); |
| context->insert_implicit_type (path.get_mappings ().get_hirid (), path_type); |
| |
| bool fully_resolved = offset >= path.get_segments ().size (); |
| if (fully_resolved) |
| { |
| translated = path_type; |
| return; |
| } |
| |
| translated |
| = resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (), |
| path.get_segments (), offset, path_type, |
| path.get_mappings (), path.get_locus ()); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::QualifiedPathInType &path) |
| { |
| HIR::QualifiedPathType qual_path_type = path.get_path_type (); |
| TyTy::BaseType *root |
| = TypeCheckType::Resolve (qual_path_type.get_type ().get ()); |
| if (root->get_kind () == TyTy::TypeKind::ERROR) |
| { |
| rust_debug_loc (path.get_locus (), "failed to resolve the root"); |
| return; |
| } |
| |
| if (!qual_path_type.has_as_clause ()) |
| { |
| // then this is just a normal path-in-expression |
| NodeId root_resolved_node_id = UNKNOWN_NODEID; |
| bool ok = resolver->lookup_resolved_type ( |
| qual_path_type.get_type ()->get_mappings ().get_nodeid (), |
| &root_resolved_node_id); |
| rust_assert (ok); |
| |
| translated = resolve_segments (root_resolved_node_id, |
| path.get_mappings ().get_hirid (), |
| path.get_segments (), 0, translated, |
| path.get_mappings (), path.get_locus ()); |
| |
| return; |
| } |
| |
| // Resolve the trait now |
| TraitReference *trait_ref |
| = TraitResolver::Resolve (*qual_path_type.get_trait ().get ()); |
| if (trait_ref->is_error ()) |
| return; |
| |
| // does this type actually implement this type-bound? |
| if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref)) |
| { |
| rust_error_at (qual_path_type.get_locus (), |
| "root does not satisfy specified trait-bound"); |
| return; |
| } |
| |
| // get the predicate for the bound |
| auto specified_bound |
| = get_predicate_from_bound (*qual_path_type.get_trait ().get ()); |
| if (specified_bound.is_error ()) |
| return; |
| |
| // inherit the bound |
| root->inherit_bounds ({specified_bound}); |
| |
| // setup the associated types |
| const TraitReference *specified_bound_ref = specified_bound.get (); |
| auto candidates = TypeBoundsProbe::Probe (root); |
| AssociatedImplTrait *associated_impl_trait = nullptr; |
| for (auto &probed_bound : candidates) |
| { |
| const 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 (); |
| 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 (root, false); |
| if (found_trait && found_self) |
| { |
| associated_impl_trait = associated; |
| break; |
| } |
| } |
| } |
| |
| if (associated_impl_trait != nullptr) |
| { |
| associated_impl_trait->setup_associated_types (root, specified_bound); |
| } |
| |
| // lookup the associated item from the specified bound |
| std::unique_ptr<HIR::TypePathSegment> &item_seg |
| = path.get_associated_segment (); |
| HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment (); |
| TyTy::TypeBoundPredicateItem item |
| = specified_bound.lookup_associated_item (item_seg_identifier.as_string ()); |
| if (item.is_error ()) |
| { |
| rust_error_at (item_seg->get_locus (), "unknown associated item"); |
| return; |
| } |
| |
| // infer the root type |
| translated = item.get_tyty_for_receiver (root); |
| |
| // turbo-fish segment path::<ty> |
| if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC) |
| { |
| HIR::TypePathSegmentGeneric &generic_seg |
| = static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ()); |
| |
| // turbo-fish segment path::<ty> |
| if (generic_seg.has_generic_args ()) |
| { |
| if (!translated->can_substitute ()) |
| { |
| rust_error_at (item_seg->get_locus (), |
| "substitutions not supported for %s", |
| translated->as_string ().c_str ()); |
| translated |
| = new TyTy::ErrorType (path.get_mappings ().get_hirid ()); |
| return; |
| } |
| translated = SubstMapper::Resolve (translated, path.get_locus (), |
| &generic_seg.get_generic_args ()); |
| } |
| } |
| |
| // continue on as a path-in-expression |
| const TraitItemReference *trait_item_ref = item.get_raw_item (); |
| NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid (); |
| bool fully_resolved = path.get_segments ().empty (); |
| if (fully_resolved) |
| { |
| resolver->insert_resolved_type (path.get_mappings ().get_nodeid (), |
| root_resolved_node_id); |
| context->insert_receiver (path.get_mappings ().get_hirid (), root); |
| return; |
| } |
| |
| translated |
| = resolve_segments (root_resolved_node_id, |
| path.get_mappings ().get_hirid (), path.get_segments (), |
| 0, translated, path.get_mappings (), path.get_locus ()); |
| } |
| |
| TyTy::BaseType * |
| TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, |
| NodeId *root_resolved_node_id) |
| { |
| TyTy::BaseType *root_tyty = nullptr; |
| *offset = 0; |
| for (size_t i = 0; i < path.get_num_segments (); i++) |
| { |
| std::unique_ptr<HIR::TypePathSegment> &seg = path.get_segments ().at (i); |
| |
| bool have_more_segments = (path.get_num_segments () - 1 != i); |
| bool is_root = *offset == 0; |
| NodeId ast_node_id = seg->get_mappings ().get_nodeid (); |
| |
| // then lookup the reference_node_id |
| NodeId ref_node_id = UNKNOWN_NODEID; |
| if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) |
| { |
| resolver->lookup_resolved_type (ast_node_id, &ref_node_id); |
| } |
| |
| // ref_node_id is the NodeId that the segments refers to. |
| if (ref_node_id == UNKNOWN_NODEID) |
| { |
| if (is_root) |
| { |
| rust_error_at (seg->get_locus (), |
| "unknown reference for resolved name: %<%s%>", |
| seg->get_ident_segment ().as_string ().c_str ()); |
| return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); |
| } |
| return root_tyty; |
| } |
| |
| // node back to HIR |
| HirId ref = UNKNOWN_HIRID; |
| if (!mappings->lookup_node_to_hir (ref_node_id, &ref)) |
| { |
| if (is_root) |
| { |
| rust_error_at (seg->get_locus (), "789 reverse lookup failure"); |
| rust_debug_loc ( |
| seg->get_locus (), |
| "failure with [%s] mappings [%s] ref_node_id [%u]", |
| seg->as_string ().c_str (), |
| seg->get_mappings ().as_string ().c_str (), ref_node_id); |
| |
| return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); |
| } |
| |
| return root_tyty; |
| } |
| |
| auto seg_is_module = (nullptr != mappings->lookup_module (ref)); |
| auto seg_is_crate = mappings->is_local_hirid_crate (ref); |
| if (seg_is_module || seg_is_crate) |
| { |
| // A::B::C::this_is_a_module::D::E::F |
| // ^^^^^^^^^^^^^^^^ |
| // Currently handling this. |
| if (have_more_segments) |
| { |
| (*offset)++; |
| continue; |
| } |
| |
| // In the case of : |
| // A::B::C::this_is_a_module |
| // ^^^^^^^^^^^^^^^^ |
| // This is an error, we are not expecting a module. |
| rust_error_at (seg->get_locus (), "expected value"); |
| return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); |
| } |
| |
| TyTy::BaseType *lookup = nullptr; |
| if (!query_type (ref, &lookup)) |
| { |
| if (is_root) |
| { |
| rust_error_at (seg->get_locus (), |
| "failed to resolve root segment"); |
| return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); |
| } |
| return root_tyty; |
| } |
| |
| // if we have a previous segment type |
| if (root_tyty != nullptr) |
| { |
| // if this next segment needs substitution we must apply the |
| // previous type arguments |
| // |
| // such as: GenericStruct::<_>::new(123, 456) |
| if (lookup->needs_generic_substitutions ()) |
| { |
| if (!root_tyty->needs_generic_substitutions ()) |
| { |
| auto used_args_in_prev_segment |
| = GetUsedSubstArgs::From (root_tyty); |
| lookup |
| = SubstMapperInternal::Resolve (lookup, |
| used_args_in_prev_segment); |
| } |
| } |
| } |
| |
| // turbo-fish segment path::<ty> |
| if (seg->is_generic_segment ()) |
| { |
| HIR::TypePathSegmentGeneric *generic_segment |
| = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ()); |
| |
| if (!lookup->can_substitute ()) |
| { |
| rust_error_at (path.get_locus (), |
| "TypePath %s declares generic arguments but the " |
| "type %s does not have any", |
| path.as_string ().c_str (), |
| lookup->as_string ().c_str ()); |
| return new TyTy::ErrorType (lookup->get_ref ()); |
| } |
| lookup = SubstMapper::Resolve (lookup, path.get_locus (), |
| &generic_segment->get_generic_args ()); |
| } |
| else if (lookup->needs_generic_substitutions ()) |
| { |
| HIR::GenericArgs empty |
| = HIR::GenericArgs::create_empty (path.get_locus ()); |
| lookup = SubstMapper::Resolve (lookup, path.get_locus (), &empty); |
| } |
| |
| *root_resolved_node_id = ref_node_id; |
| *offset = *offset + 1; |
| root_tyty = lookup; |
| } |
| |
| return root_tyty; |
| } |
| |
| TyTy::BaseType * |
| TypeCheckType::resolve_segments ( |
| NodeId root_resolved_node_id, HirId expr_id, |
| std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset, |
| TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, |
| Location expr_locus) |
| { |
| NodeId resolved_node_id = root_resolved_node_id; |
| TyTy::BaseType *prev_segment = tyseg; |
| for (size_t i = offset; i < segments.size (); i++) |
| { |
| std::unique_ptr<HIR::TypePathSegment> &seg = segments.at (i); |
| |
| bool reciever_is_generic |
| = prev_segment->get_kind () == TyTy::TypeKind::PARAM; |
| bool probe_bounds = true; |
| bool probe_impls = !reciever_is_generic; |
| bool ignore_mandatory_trait_items = !reciever_is_generic; |
| |
| // probe the path is done in two parts one where we search impls if no |
| // candidate is found then we search extensions from traits |
| auto candidates |
| = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), |
| probe_impls, false, |
| ignore_mandatory_trait_items); |
| if (candidates.size () == 0) |
| { |
| candidates |
| = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), |
| false, probe_bounds, |
| ignore_mandatory_trait_items); |
| |
| if (candidates.size () == 0) |
| { |
| rust_error_at ( |
| seg->get_locus (), |
| "failed to resolve path segment using an impl Probe"); |
| return new TyTy::ErrorType (expr_id); |
| } |
| } |
| |
| if (candidates.size () > 1) |
| { |
| ReportMultipleCandidateError::Report (candidates, |
| seg->get_ident_segment (), |
| seg->get_locus ()); |
| return new TyTy::ErrorType (expr_id); |
| } |
| |
| auto &candidate = *candidates.begin (); |
| prev_segment = tyseg; |
| tyseg = candidate.ty; |
| |
| if (candidate.is_impl_candidate ()) |
| { |
| resolved_node_id |
| = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid (); |
| } |
| else |
| { |
| resolved_node_id |
| = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); |
| } |
| |
| if (seg->is_generic_segment ()) |
| { |
| HIR::TypePathSegmentGeneric *generic_segment |
| = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ()); |
| |
| if (!tyseg->can_substitute ()) |
| { |
| rust_error_at (expr_locus, "substitutions not supported for %s", |
| tyseg->as_string ().c_str ()); |
| return new TyTy::ErrorType (expr_id); |
| } |
| |
| tyseg = SubstMapper::Resolve (tyseg, expr_locus, |
| &generic_segment->get_generic_args ()); |
| if (tyseg->get_kind () == TyTy::TypeKind::ERROR) |
| return new TyTy::ErrorType (expr_id); |
| } |
| } |
| |
| context->insert_receiver (expr_mappings.get_hirid (), prev_segment); |
| if (tyseg->needs_generic_substitutions ()) |
| { |
| // Location locus = segments.back ()->get_locus (); |
| if (!prev_segment->needs_generic_substitutions ()) |
| { |
| auto used_args_in_prev_segment |
| = GetUsedSubstArgs::From (prev_segment); |
| if (!used_args_in_prev_segment.is_error ()) |
| tyseg |
| = SubstMapperInternal::Resolve (tyseg, used_args_in_prev_segment); |
| } |
| |
| if (tyseg->get_kind () == TyTy::TypeKind::ERROR) |
| return new TyTy::ErrorType (expr_id); |
| } |
| |
| rust_assert (resolved_node_id != UNKNOWN_NODEID); |
| |
| // lookup if the name resolver was able to canonically resolve this or not |
| NodeId path_resolved_id = UNKNOWN_NODEID; |
| if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (), |
| &path_resolved_id)) |
| { |
| rust_assert (path_resolved_id == resolved_node_id); |
| } |
| // check the type scope |
| else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (), |
| &path_resolved_id)) |
| { |
| rust_assert (path_resolved_id == resolved_node_id); |
| } |
| else |
| { |
| // name scope first |
| if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) |
| { |
| resolver->insert_resolved_name (expr_mappings.get_nodeid (), |
| resolved_node_id); |
| } |
| // check the type scope |
| else if (resolver->get_type_scope ().decl_was_declared_here ( |
| resolved_node_id)) |
| { |
| resolver->insert_resolved_type (expr_mappings.get_nodeid (), |
| resolved_node_id); |
| } |
| } |
| |
| return tyseg; |
| } |
| |
| void |
| TypeCheckType::visit (HIR::TraitObjectType &type) |
| { |
| std::vector<TyTy::TypeBoundPredicate> specified_bounds; |
| for (auto &bound : type.get_type_param_bounds ()) |
| { |
| if (bound->get_bound_type () |
| != HIR::TypeParamBound::BoundType::TRAITBOUND) |
| continue; |
| |
| HIR::TypeParamBound &b = *bound.get (); |
| HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b); |
| |
| TyTy::TypeBoundPredicate predicate |
| = get_predicate_from_bound (trait_bound.get_path ()); |
| |
| if (!predicate.is_error () |
| && predicate.is_object_safe (true, type.get_locus ())) |
| specified_bounds.push_back (std::move (predicate)); |
| } |
| |
| RustIdent ident{CanonicalPath::create_empty (), type.get_locus ()}; |
| translated |
| = new TyTy::DynamicObjectType (type.get_mappings ().get_hirid (), ident, |
| std::move (specified_bounds)); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::ArrayType &type) |
| { |
| auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ()); |
| if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) |
| return; |
| |
| TyTy::BaseType *expected_ty = nullptr; |
| bool ok = context->lookup_builtin ("usize", &expected_ty); |
| rust_assert (ok); |
| context->insert_type (type.get_size_expr ()->get_mappings (), expected_ty); |
| |
| unify_site (type.get_size_expr ()->get_mappings ().get_hirid (), |
| TyTy::TyWithLocation (expected_ty), |
| TyTy::TyWithLocation (capacity_type, |
| type.get_size_expr ()->get_locus ()), |
| type.get_size_expr ()->get_locus ()); |
| |
| TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); |
| translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), |
| type.get_locus (), *type.get_size_expr (), |
| TyTy::TyVar (base->get_ref ())); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::SliceType &type) |
| { |
| TyTy::BaseType *base |
| = TypeCheckType::Resolve (type.get_element_type ().get ()); |
| translated |
| = new TyTy::SliceType (type.get_mappings ().get_hirid (), type.get_locus (), |
| TyTy::TyVar (base->get_ref ())); |
| } |
| void |
| TypeCheckType::visit (HIR::ReferenceType &type) |
| { |
| TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ()); |
| translated |
| = new TyTy::ReferenceType (type.get_mappings ().get_hirid (), |
| TyTy::TyVar (base->get_ref ()), type.get_mut ()); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::RawPointerType &type) |
| { |
| TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ()); |
| translated |
| = new TyTy::PointerType (type.get_mappings ().get_hirid (), |
| TyTy::TyVar (base->get_ref ()), type.get_mut ()); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::InferredType &type) |
| { |
| translated = new TyTy::InferType (type.get_mappings ().get_hirid (), |
| TyTy::InferType::InferTypeKind::GENERAL, |
| type.get_locus ()); |
| } |
| |
| void |
| TypeCheckType::visit (HIR::NeverType &type) |
| { |
| TyTy::BaseType *lookup = nullptr; |
| bool ok = context->lookup_builtin ("!", &lookup); |
| rust_assert (ok); |
| |
| translated = lookup->clone (); |
| } |
| |
| TyTy::ParamType * |
| TypeResolveGenericParam::Resolve (HIR::GenericParam *param) |
| { |
| TypeResolveGenericParam resolver; |
| switch (param->get_kind ()) |
| { |
| case HIR::GenericParam::GenericKind::TYPE: |
| resolver.visit (static_cast<HIR::TypeParam &> (*param)); |
| break; |
| |
| case HIR::GenericParam::GenericKind::CONST: |
| resolver.visit (static_cast<HIR::ConstGenericParam &> (*param)); |
| break; |
| |
| case HIR::GenericParam::GenericKind::LIFETIME: |
| resolver.visit (static_cast<HIR::LifetimeParam &> (*param)); |
| break; |
| } |
| return resolver.resolved; |
| } |
| |
| void |
| TypeResolveGenericParam::visit (HIR::LifetimeParam ¶m) |
| { |
| // nothing to do |
| } |
| |
| void |
| TypeResolveGenericParam::visit (HIR::ConstGenericParam ¶m) |
| { |
| // TODO |
| } |
| |
| void |
| TypeResolveGenericParam::visit (HIR::TypeParam ¶m) |
| { |
| if (param.has_type ()) |
| TypeCheckType::Resolve (param.get_type ().get ()); |
| |
| std::vector<TyTy::TypeBoundPredicate> specified_bounds; |
| if (param.has_type_param_bounds ()) |
| { |
| for (auto &bound : param.get_type_param_bounds ()) |
| { |
| switch (bound->get_bound_type ()) |
| { |
| case HIR::TypeParamBound::BoundType::TRAITBOUND: { |
| HIR::TraitBound *b |
| = static_cast<HIR::TraitBound *> (bound.get ()); |
| |
| TyTy::TypeBoundPredicate predicate |
| = get_predicate_from_bound (b->get_path ()); |
| if (!predicate.is_error ()) |
| specified_bounds.push_back (std::move (predicate)); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| resolved |
| = new TyTy::ParamType (param.get_type_representation (), param.get_locus (), |
| param.get_mappings ().get_hirid (), param, |
| specified_bounds); |
| } |
| |
| void |
| ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem &item) |
| { |
| ResolveWhereClauseItem resolver; |
| switch (item.get_item_type ()) |
| { |
| case HIR::WhereClauseItem::LIFETIME: |
| resolver.visit (static_cast<HIR::LifetimeWhereClauseItem &> (item)); |
| break; |
| |
| case HIR::WhereClauseItem::TYPE_BOUND: |
| resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (item)); |
| break; |
| } |
| } |
| |
| void |
| ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item) |
| {} |
| |
| void |
| ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) |
| { |
| auto &binding_type_path = item.get_bound_type (); |
| TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ()); |
| |
| std::vector<TyTy::TypeBoundPredicate> specified_bounds; |
| for (auto &bound : item.get_type_param_bounds ()) |
| { |
| switch (bound->get_bound_type ()) |
| { |
| case HIR::TypeParamBound::BoundType::TRAITBOUND: { |
| HIR::TraitBound *b = static_cast<HIR::TraitBound *> (bound.get ()); |
| |
| TyTy::TypeBoundPredicate predicate |
| = get_predicate_from_bound (b->get_path ()); |
| if (!predicate.is_error ()) |
| specified_bounds.push_back (std::move (predicate)); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| binding->inherit_bounds (specified_bounds); |
| |
| // When we apply these bounds we must lookup which type this binding |
| // resolves to, as this is the type which will be used during resolution |
| // of the block. |
| NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid (); |
| |
| // then lookup the reference_node_id |
| NodeId ref_node_id = UNKNOWN_NODEID; |
| if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) |
| { |
| // FIXME |
| rust_error_at (Location (), |
| "Failed to lookup type reference for node: %s", |
| binding_type_path->as_string ().c_str ()); |
| return; |
| } |
| |
| // node back to HIR |
| HirId ref; |
| if (!mappings->lookup_node_to_hir (ref_node_id, &ref)) |
| { |
| // FIXME |
| rust_error_at (Location (), "where-clause reverse lookup failure"); |
| return; |
| } |
| |
| // the base reference for this name _must_ have a type set |
| TyTy::BaseType *lookup; |
| if (!context->lookup_type (ref, &lookup)) |
| { |
| rust_error_at (mappings->lookup_location (ref), |
| "Failed to resolve where-clause binding type: %s", |
| binding_type_path->as_string ().c_str ()); |
| return; |
| } |
| |
| // FIXME |
| // rust_assert (binding->is_equal (*lookup)); |
| lookup->inherit_bounds (specified_bounds); |
| } |
| |
| } // namespace Resolver |
| } // namespace Rust |