gccrs: Support for Sized builtin marker trait

When implementing general bounds checking as part of unify calls, we did
not check associated types on bounds which lead to alot of missed error
checking. This now recursively checks the bounds and the associated types
with a decent error message. This also required us to implement the Sized
marker trait to keep existing test-cases happy.

Fixes #1725

Signed-off-by: Philip Herron <herron.philip@googlemail.com>

gcc/rust/ChangeLog:

	* 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

gcc/testsuite/ChangeLog:

	* rust/compile/issue-1725-1.rs: New test.
	* rust/compile/issue-1725-2.rs: New test.
This commit is contained in:
Philip Herron
2023-02-13 17:51:19 +00:00
committed by Arthur Cohen
parent e90d06c544
commit 4b25fc15b9
14 changed files with 476 additions and 186 deletions

View File

@@ -343,14 +343,26 @@ TraitReference::on_resolved ()
}
void
TraitReference::clear_associated_types ()
TraitReference::clear_associated_types () const
{
for (auto &item : item_refs)
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 ();
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);
}
}

View File

@@ -106,7 +106,7 @@ public:
void associated_type_set (TyTy::BaseType *ty) const;
void associated_type_reset () const;
void associated_type_reset (bool only_projections) const;
bool is_object_safe () const;
@@ -212,7 +212,9 @@ public:
void on_resolved ();
void clear_associated_types ();
void clear_associated_types () const;
void clear_associated_type_projections () const;
bool is_equal (const TraitReference &other) const;

View File

@@ -161,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 ())
@@ -182,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;
@@ -365,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);
@@ -374,7 +381,21 @@ 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 ();
}
}
}
TyTy::BaseType *

View File

@@ -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;

View File

@@ -1095,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)
{
@@ -1659,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)
{

View File

@@ -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,
@@ -514,8 +619,8 @@ 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
// 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 ();

View File

@@ -119,11 +119,6 @@ SubstitutionParamMapping::fill_param_ty (
{
type.inherit_bounds (*param);
}
else
{
if (!param->bounds_compatible (type, locus, true))
return false;
}
if (type.get_kind () == TypeKind::PARAM)
{
@@ -133,8 +128,15 @@ SubstitutionParamMapping::fill_param_ty (
else
{
// check the substitution is compatible with bounds
if (!param->bounds_compatible (type, locus, true))
return false;
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 ())
@@ -870,10 +872,149 @@ SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
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 ()
{
auto context = Resolver::TypeCheckContext::get ();
for (const auto &subst : get_substs ())
{
const TyTy::ParamType *pty = subst.get_param_ty ();
@@ -887,136 +1028,16 @@ SubstitutionRef::monomorphize ()
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);
std::vector<Resolver::AssociatedImplTrait *> associated_impl_traits;
for (auto &probed_bound : candidates)
bool error_flag = false;
auto associated
= lookup_associated_impl (subst, bound, binding, &error_flag);
if (associated != nullptr)
{
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);
}
}
associated->setup_associated_types (binding, bound);
}
if (!associated_impl_traits.empty ())
{
// 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 (associated_impl_traits.size () == 1)
{
Resolver::AssociatedImplTrait *associate_impl_trait
= associated_impl_traits.at (0);
associate_impl_trait->setup_associated_types (binding, bound);
}
else
{
// 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 (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 ());
return false;
}
associate_impl_trait->setup_associated_types (binding, bound);
}
}
if (error_flag)
return false;
}
}

View File

@@ -298,7 +298,13 @@ public:
// TODO comment
BaseType *infer_substitions (Location locus);
// TODO comment
// 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
@@ -308,6 +314,10 @@ public:
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;
};

View File

@@ -31,6 +31,7 @@
#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"
@@ -266,6 +267,7 @@ BaseType::get_locus () const
return ident.locus;
}
// FIXME this is missing locus
bool
BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
{
@@ -277,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;
@@ -2827,18 +2884,18 @@ ParamType::ParamType (std::string symbol, Location locus, HirId ref,
{Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
locus},
specified_bounds, refs),
symbol (symbol), param (param)
is_trait_self (false), symbol (symbol), param (param)
{}
ParamType::ParamType (std::string symbol, Location locus, HirId ref,
HirId ty_ref, HIR::GenericParam &param,
ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus,
HirId ref, HirId ty_ref, HIR::GenericParam &param,
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),
symbol (symbol), param (param)
is_trait_self (is_trait_self), symbol (symbol), param (param)
{}
HIR::GenericParam &
@@ -2906,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 *
@@ -2997,6 +3055,18 @@ 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)

View File

@@ -267,8 +267,8 @@ public:
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref,
HIR::GenericParam &param,
ParamType (bool is_trait_self, std::string symbol, Location locus, HirId ref,
HirId ty_ref, HIR::GenericParam &param,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
@@ -298,7 +298,11 @@ public:
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 &param;
};

View File

@@ -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

View File

@@ -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;

View File

@@ -0,0 +1,19 @@
mod core {
mod ops {
#[lang = "add"]
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
}
}
pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
a + a
}
pub fn main() {
foo(123f32);
// { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-1 }
}

View File

@@ -0,0 +1,28 @@
mod core {
mod ops {
#[lang = "add"]
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
}
}
impl core::ops::Add for f32 {
type Output = f32;
fn add(self, rhs: Self) -> Self::Output {
self + rhs
}
}
pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
a + a
}
pub fn main() {
foo(123f32);
// { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
// { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-2 }
}