Skip to content

Commit 8086790

Browse files
committed
Fix unconstrained type parameter checks
This patch removes our old method of checking for unconstrained type parameters which only worked for the basic cases such as: impl<T> Foo { } But checking for unconstrained types is more complex, we need to handle covariant types such as: impl<T> *T { } Or struct foo<X,Y>(X,Y); impl<T> foo<&T,*T> {} This rewrites the algorithm to take advantage of our substition abstractions and HirIds so we can map the ids of the type-params to be constrained and look at the trait-references used-arguments when the generics are applied (or they may be empty) and then do the same for any used arguments on an algebraic data type. Fixes #1019
1 parent 21cf0e6 commit 8086790

12 files changed

+289
-159
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ GRS_OBJS = \
9999
rust/rust-hir-type-check-pattern.o \
100100
rust/rust-hir-type-check-expr.o \
101101
rust/rust-hir-dot-operator.o \
102+
rust/rust-hir-type-check-base.o \
102103
rust/rust-autoderef.o \
103104
rust/rust-substitution-mapper.o \
104105
rust/rust-lint-marklive.o \
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "rust-hir-type-check-base.h"
20+
21+
namespace Rust {
22+
namespace Resolver {
23+
24+
bool
25+
TypeCheckBase::check_for_unconstrained (
26+
const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
27+
const TyTy::SubstitutionArgumentMappings &constraint_a,
28+
const TyTy::SubstitutionArgumentMappings &constraint_b,
29+
const TyTy::BaseType *reference)
30+
{
31+
std::set<HirId> symbols_to_constrain;
32+
std::map<HirId, Location> symbol_to_location;
33+
for (const auto &p : params_to_constrain)
34+
{
35+
HirId ref = p.get_param_ty ()->get_ref ();
36+
symbols_to_constrain.insert (ref);
37+
symbol_to_location.insert ({ref, p.get_param_locus ()});
38+
}
39+
40+
// set up the set of constrained symbols
41+
std::set<HirId> constrained_symbols;
42+
for (const auto &c : constraint_a.get_mappings ())
43+
{
44+
const TyTy::BaseType *arg = c.get_tyty ();
45+
if (arg != nullptr)
46+
{
47+
const TyTy::BaseType *p = arg->get_root ();
48+
constrained_symbols.insert (p->get_ty_ref ());
49+
}
50+
}
51+
for (const auto &c : constraint_b.get_mappings ())
52+
{
53+
const TyTy::BaseType *arg = c.get_tyty ();
54+
if (arg != nullptr)
55+
{
56+
const TyTy::BaseType *p = arg->get_root ();
57+
constrained_symbols.insert (p->get_ty_ref ());
58+
}
59+
}
60+
61+
const auto root = reference->get_root ();
62+
if (root->get_kind () == TyTy::TypeKind::PARAM)
63+
{
64+
const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
65+
constrained_symbols.insert (p->get_ty_ref ());
66+
}
67+
68+
// check for unconstrained
69+
bool unconstrained = false;
70+
for (auto &sym : symbols_to_constrain)
71+
{
72+
bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
73+
if (!used)
74+
{
75+
Location locus = symbol_to_location.at (sym);
76+
rust_error_at (locus, "unconstrained type parameter");
77+
unconstrained = true;
78+
}
79+
}
80+
return unconstrained;
81+
}
82+
83+
} // namespace Resolver
84+
} // namespace Rust

gcc/rust/typecheck/rust-hir-type-check-base.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ class TypeCheckBase : public HIR::HIRFullVisitorBase
4747

4848
TraitReference *resolve_trait_path (HIR::TypePath &);
4949

50+
TyTy::TypeBoundPredicate get_predicate_from_bound (HIR::TypePath &path);
51+
52+
bool check_for_unconstrained (
53+
const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
54+
const TyTy::SubstitutionArgumentMappings &constraint_a,
55+
const TyTy::SubstitutionArgumentMappings &constraint_b,
56+
const TyTy::BaseType *reference);
57+
5058
Analysis::Mappings *mappings;
5159
Resolver *resolver;
5260
TypeCheckContext *context;

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

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,34 +70,15 @@ class TypeCheckItem : public TypeCheckBase
7070
}
7171
}
7272

73-
std::vector<TyTy::TypeBoundPredicate> specified_bounds;
73+
auto specified_bound = TyTy::TypeBoundPredicate::error ();
7474
TraitReference *trait_reference = &TraitReference::error_node ();
7575
if (impl_block.has_trait_ref ())
7676
{
7777
std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
7878
trait_reference = TraitResolver::Resolve (*ref.get ());
7979
rust_assert (!trait_reference->is_error ());
8080

81-
// setup the bound
82-
TyTy::TypeBoundPredicate predicate (*trait_reference,
83-
ref->get_locus ());
84-
auto &final_seg = ref->get_final_segment ();
85-
if (final_seg->is_generic_segment ())
86-
{
87-
auto final_generic_seg
88-
= static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ());
89-
if (final_generic_seg->has_generic_args ())
90-
{
91-
HIR::GenericArgs &generic_args
92-
= final_generic_seg->get_generic_args ();
93-
94-
// this is applying generic arguments to a trait
95-
// reference
96-
predicate.apply_generic_arguments (&generic_args);
97-
}
98-
}
99-
100-
specified_bounds.push_back (std::move (predicate));
81+
specified_bound = get_predicate_from_bound (*ref.get ());
10182
}
10283

10384
TyTy::BaseType *self = nullptr;
@@ -108,11 +89,25 @@ class TypeCheckItem : public TypeCheckBase
10889
"failed to resolve Self for ImplBlock");
10990
return;
11091
}
111-
// inherit the bounds
112-
self->inherit_bounds (specified_bounds);
11392

93+
// inherit the bounds
94+
if (!specified_bound.is_error ())
95+
self->inherit_bounds ({specified_bound});
96+
97+
// check for any unconstrained type-params
98+
const TyTy::SubstitutionArgumentMappings trait_constraints
99+
= specified_bound.get_substitution_arguments ();
100+
const TyTy::SubstitutionArgumentMappings impl_constraints
101+
= GetUsedSubstArgs::From (self);
102+
103+
bool impl_block_has_unconstrained_typarams
104+
= check_for_unconstrained (substitutions, trait_constraints,
105+
impl_constraints, self);
106+
if (impl_block_has_unconstrained_typarams)
107+
return;
108+
109+
// validate the impl items
114110
bool is_trait_impl_block = !trait_reference->is_error ();
115-
116111
std::vector<const TraitItemReference *> trait_item_refs;
117112
for (auto &impl_item : impl_block.get_impl_items ())
118113
{

gcc/rust/typecheck/rust-hir-type-check-toplevel.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,8 @@ class TypeCheckTopLevel : public TypeCheckBase
468468
ResolveWhereClauseItem::Resolve (*where_clause_item.get ());
469469
}
470470

471-
auto self
472-
= TypeCheckType::Resolve (impl_block.get_type ().get (), &substitutions);
473-
if (self == nullptr || self->get_kind () == TyTy::TypeKind::ERROR)
471+
auto self = TypeCheckType::Resolve (impl_block.get_type ().get ());
472+
if (self->get_kind () == TyTy::TypeKind::ERROR)
474473
return;
475474

476475
for (auto &impl_item : impl_block.get_impl_items ())

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

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,6 @@ TypeCheckType::visit (HIR::TypePath &path)
8484
}
8585

8686
translated = SubstMapper::Resolve (path_type, path.get_locus (), &args);
87-
if (translated->get_kind () != TyTy::TypeKind::ERROR
88-
&& mappings != nullptr)
89-
{
90-
check_for_unconstrained (args.get_type_args ());
91-
}
9287
}
9388
else if (!args.is_empty ())
9489
{
@@ -548,26 +543,11 @@ TypeCheckType::visit (HIR::TraitObjectType &type)
548543
HIR::TypeParamBound &b = *bound.get ();
549544
HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b);
550545

551-
auto &type_path = trait_bound.get_path ();
552-
TraitReference *trait = resolve_trait_path (type_path);
553-
TyTy::TypeBoundPredicate predicate (*trait, trait_bound.get_locus ());
554-
auto &final_seg = type_path.get_final_segment ();
555-
if (final_seg->is_generic_segment ())
556-
{
557-
auto final_generic_seg
558-
= static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ());
559-
if (final_generic_seg->has_generic_args ())
560-
{
561-
HIR::GenericArgs &generic_args
562-
= final_generic_seg->get_generic_args ();
563-
564-
// this is applying generic arguments to a trait
565-
// reference
566-
predicate.apply_generic_arguments (&generic_args);
567-
}
568-
}
546+
TyTy::TypeBoundPredicate predicate
547+
= get_predicate_from_bound (trait_bound.get_path ());
569548

570-
if (predicate.is_object_safe (true, type.get_locus ()))
549+
if (!predicate.is_error ()
550+
&& predicate.is_object_safe (true, type.get_locus ()))
571551
specified_bounds.push_back (std::move (predicate));
572552
}
573553

gcc/rust/typecheck/rust-hir-type-check-type.h

Lines changed: 12 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,9 @@ class TypeCheckType : public TypeCheckBase
5757
using Rust::Resolver::TypeCheckBase::visit;
5858

5959
public:
60-
static TyTy::BaseType *
61-
Resolve (HIR::Type *type,
62-
std::vector<TyTy::SubstitutionParamMapping> *subst_mappings
63-
= nullptr)
60+
static TyTy::BaseType *Resolve (HIR::Type *type)
6461
{
65-
TypeCheckType resolver (type->get_mappings ().get_hirid (), subst_mappings);
62+
TypeCheckType resolver (type->get_mappings ().get_hirid ());
6663
type->accept_vis (resolver);
6764
rust_assert (resolver.translated != nullptr);
6865
resolver.context->insert_type (type->get_mappings (), resolver.translated);
@@ -159,43 +156,10 @@ class TypeCheckType : public TypeCheckBase
159156
void visit (HIR::TraitObjectType &type) override;
160157

161158
private:
162-
TypeCheckType (HirId id,
163-
std::vector<TyTy::SubstitutionParamMapping> *subst_mappings)
164-
: TypeCheckBase (), subst_mappings (subst_mappings),
165-
translated (new TyTy::ErrorType (id))
159+
TypeCheckType (HirId id)
160+
: TypeCheckBase (), translated (new TyTy::ErrorType (id))
166161
{}
167162

168-
void
169-
check_for_unconstrained (std::vector<std::unique_ptr<HIR::Type>> &type_args)
170-
{
171-
std::map<std::string, Location> param_location_map;
172-
std::set<std::string> param_tys;
173-
174-
if (subst_mappings != nullptr)
175-
{
176-
for (auto &mapping : *subst_mappings)
177-
{
178-
std::string sym = mapping.get_param_ty ()->get_symbol ();
179-
param_tys.insert (sym);
180-
param_location_map[sym] = mapping.get_generic_param ().get_locus ();
181-
}
182-
}
183-
184-
std::set<std::string> args;
185-
for (auto &arg : type_args)
186-
args.insert (arg->as_string ());
187-
188-
for (auto &exp : param_tys)
189-
{
190-
bool used = args.find (exp) != args.end ();
191-
if (!used)
192-
{
193-
Location locus = param_location_map.at (exp);
194-
rust_error_at (locus, "unconstrained type parameter");
195-
}
196-
}
197-
}
198-
199163
TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset,
200164
NodeId *root_resolved_node_id);
201165

@@ -205,7 +169,6 @@ class TypeCheckType : public TypeCheckBase
205169
TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings,
206170
Location expr_locus);
207171

208-
std::vector<TyTy::SubstitutionParamMapping> *subst_mappings;
209172
TyTy::BaseType *translated;
210173
};
211174

@@ -245,28 +208,10 @@ class TypeResolveGenericParam : public TypeCheckBase
245208
HIR::TraitBound *b
246209
= static_cast<HIR::TraitBound *> (bound.get ());
247210

248-
auto &type_path = b->get_path ();
249-
TraitReference *trait = resolve_trait_path (type_path);
250-
TyTy::TypeBoundPredicate predicate (*trait, b->get_locus ());
251-
252-
auto &final_seg = type_path.get_final_segment ();
253-
if (final_seg->is_generic_segment ())
254-
{
255-
auto final_generic_seg
256-
= static_cast<HIR::TypePathSegmentGeneric *> (
257-
final_seg.get ());
258-
if (final_generic_seg->has_generic_args ())
259-
{
260-
HIR::GenericArgs &generic_args
261-
= final_generic_seg->get_generic_args ();
262-
263-
// this is applying generic arguments to a trait
264-
// reference
265-
predicate.apply_generic_arguments (&generic_args);
266-
}
267-
}
268-
269-
specified_bounds.push_back (std::move (predicate));
211+
TyTy::TypeBoundPredicate predicate
212+
= get_predicate_from_bound (b->get_path ());
213+
if (!predicate.is_error ())
214+
specified_bounds.push_back (std::move (predicate));
270215
}
271216
break;
272217

@@ -315,28 +260,10 @@ class ResolveWhereClauseItem : public TypeCheckBase
315260
HIR::TraitBound *b
316261
= static_cast<HIR::TraitBound *> (bound.get ());
317262

318-
auto &type_path = b->get_path ();
319-
TraitReference *trait = resolve_trait_path (type_path);
320-
TyTy::TypeBoundPredicate predicate (*trait, b->get_locus ());
321-
322-
auto &final_seg = type_path.get_final_segment ();
323-
if (final_seg->is_generic_segment ())
324-
{
325-
auto final_generic_seg
326-
= static_cast<HIR::TypePathSegmentGeneric *> (
327-
final_seg.get ());
328-
if (final_generic_seg->has_generic_args ())
329-
{
330-
HIR::GenericArgs &generic_args
331-
= final_generic_seg->get_generic_args ();
332-
333-
// this is applying generic arguments to a trait
334-
// reference
335-
predicate.apply_generic_arguments (&generic_args);
336-
}
337-
}
338-
339-
specified_bounds.push_back (std::move (predicate));
263+
TyTy::TypeBoundPredicate predicate
264+
= get_predicate_from_bound (b->get_path ());
265+
if (!predicate.is_error ())
266+
specified_bounds.push_back (std::move (predicate));
340267
}
341268
break;
342269

0 commit comments

Comments
 (0)