Skip to content

Commit bb01719

Browse files
committed
gccrs: Add check for placeholder (infer) type in return position
It is not allowed to have a declared inference variable in the return position of a function as this may never get infered you need good points of truth. Ideally if we get a student for GSoC 25 we will get the Default Hir Visitor so that we can grab the HIR::InferredType locus instead of using the ref location lookups. Fixes #402 gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): add diagnostic * typecheck/rust-tyty.cc (BaseType::contains_infer): new helper to grab first infer var * typecheck/rust-tyty.h: prototype gcc/testsuite/ChangeLog: * rust/compile/issue-402.rs: New test. Signed-off-by: Philip Herron <[email protected]>
1 parent 50a90f1 commit bb01719

File tree

4 files changed

+134
-0
lines changed

4 files changed

+134
-0
lines changed

gcc/rust/typecheck/rust-hir-type-check-item.cc

+32
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,38 @@ TypeCheckItem::visit (HIR::Function &function)
649649
context->switch_to_fn_body ();
650650
auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ());
651651

652+
// emit check for
653+
// error[E0121]: the type placeholder `_` is not allowed within types on item
654+
const auto placeholder = ret_type->contains_infer ();
655+
if (placeholder != nullptr && function.has_return_type ())
656+
{
657+
// FIXME
658+
// this will be a great place for the Default Hir Visitor we want to
659+
// grab the locations of the placeholders (HIR::InferredType) their
660+
// location, for now maybe we can use their hirid to lookup the location
661+
location_t placeholder_locus
662+
= mappings.lookup_location (placeholder->get_ref ());
663+
location_t type_locus = function.get_return_type ().get_locus ();
664+
rich_location r (line_table, placeholder_locus);
665+
666+
bool have_expected_type
667+
= block_expr_ty != nullptr && !block_expr_ty->is<TyTy::ErrorType> ();
668+
if (!have_expected_type)
669+
{
670+
r.add_range (type_locus);
671+
}
672+
else
673+
{
674+
std::string fixit
675+
= "replace with the correct type " + block_expr_ty->get_name ();
676+
r.add_fixit_replace (type_locus, fixit.c_str ());
677+
}
678+
679+
rust_error_at (r, ErrorCode::E0121,
680+
"the type placeholder %<_%> is not allowed within types "
681+
"on item signatures");
682+
}
683+
652684
location_t fn_return_locus = function.has_function_return_type ()
653685
? function.get_return_type ().get_locus ()
654686
: function.get_locus ();

gcc/rust/typecheck/rust-tyty.cc

+85
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,91 @@ BaseType::debug () const
682682
debug_str ().c_str ());
683683
}
684684

685+
const TyTy::BaseType *
686+
BaseType::contains_infer () const
687+
{
688+
const TyTy::BaseType *x = destructure ();
689+
690+
if (auto fn = x->try_as<const FnType> ())
691+
{
692+
for (const auto &param : fn->get_params ())
693+
{
694+
auto infer = param.get_type ()->contains_infer ();
695+
if (infer)
696+
return infer;
697+
}
698+
return fn->get_return_type ()->contains_infer ();
699+
}
700+
else if (auto fn = x->try_as<const FnPtr> ())
701+
{
702+
for (const auto &param : fn->get_params ())
703+
{
704+
auto infer = param.get_tyty ()->contains_infer ();
705+
if (infer)
706+
return infer;
707+
}
708+
return fn->get_return_type ()->contains_infer ();
709+
}
710+
else if (auto adt = x->try_as<const ADTType> ())
711+
{
712+
for (auto &variant : adt->get_variants ())
713+
{
714+
bool is_num_variant
715+
= variant->get_variant_type () == VariantDef::VariantType::NUM;
716+
if (is_num_variant)
717+
continue;
718+
719+
for (auto &field : variant->get_fields ())
720+
{
721+
const BaseType *field_type = field->get_field_type ();
722+
auto infer = (field_type->contains_infer ());
723+
if (infer)
724+
return infer;
725+
}
726+
}
727+
return nullptr;
728+
}
729+
else if (auto arr = x->try_as<const ArrayType> ())
730+
{
731+
return arr->get_element_type ()->contains_infer ();
732+
}
733+
else if (auto slice = x->try_as<const SliceType> ())
734+
{
735+
return slice->get_element_type ()->contains_infer ();
736+
}
737+
else if (auto ptr = x->try_as<const PointerType> ())
738+
{
739+
return ptr->get_base ()->contains_infer ();
740+
}
741+
else if (auto ref = x->try_as<const ReferenceType> ())
742+
{
743+
return ref->get_base ()->contains_infer ();
744+
}
745+
else if (auto tuple = x->try_as<const TupleType> ())
746+
{
747+
for (size_t i = 0; i < tuple->num_fields (); i++)
748+
{
749+
auto infer = (tuple->get_field (i)->contains_infer ());
750+
if (infer)
751+
return infer;
752+
}
753+
return nullptr;
754+
}
755+
else if (auto closure = x->try_as<const ClosureType> ())
756+
{
757+
auto infer = (closure->get_parameters ().contains_infer ());
758+
if (infer)
759+
return infer;
760+
return closure->get_result_type ().contains_infer ();
761+
}
762+
else if (x->is<InferType> ())
763+
{
764+
return x;
765+
}
766+
767+
return nullptr;
768+
}
769+
685770
bool
686771
BaseType::is_concrete () const
687772
{

gcc/rust/typecheck/rust-tyty.h

+3
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class BaseType : public TypeBoundsMappings
137137
void inherit_bounds (
138138
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
139139

140+
// contains_infer checks if there is an inference variable inside the type
141+
const TyTy::BaseType *contains_infer () const;
142+
140143
// is_unit returns whether this is just a unit-struct
141144
bool is_unit () const;
142145

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[lang = "sized"]
2+
pub trait Sized {}
3+
4+
struct GenericStruct<T>(T, usize);
5+
6+
pub fn test() -> GenericStruct<_> {
7+
// { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 }
8+
GenericStruct(1, 2)
9+
}
10+
11+
fn square(num: i32) -> _ {
12+
// { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 }
13+
num * num
14+
}

0 commit comments

Comments
 (0)