1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
19 #include "rust-hir-type-check-base.h"
20 #include "rust-hir-type-check-expr.h"
21 #include "rust-hir-type-check-type.h"
22 #include "rust-hir-trait-resolve.h"
23 #include "rust-type-util.h"
24 #include "rust-attribute-values.h"
29 TypeCheckBase::TypeCheckBase ()
30 : mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
31 context (TypeCheckContext::get ())
35 TypeCheckBase::check_for_unconstrained (
36 const std::vector
<TyTy::SubstitutionParamMapping
> ¶ms_to_constrain
,
37 const TyTy::SubstitutionArgumentMappings
&constraint_a
,
38 const TyTy::SubstitutionArgumentMappings
&constraint_b
,
39 const TyTy::BaseType
*reference
)
41 bool check_result
= false;
43 = context
->have_checked_for_unconstrained (reference
->get_ref (),
48 std::set
<HirId
> symbols_to_constrain
;
49 std::map
<HirId
, location_t
> symbol_to_location
;
50 for (const auto &p
: params_to_constrain
)
52 HirId ref
= p
.get_param_ty ()->get_ref ();
53 symbols_to_constrain
.insert (ref
);
54 symbol_to_location
.insert ({ref
, p
.get_param_locus ()});
57 // set up the set of constrained symbols
58 std::set
<HirId
> constrained_symbols
;
59 for (const auto &c
: constraint_a
.get_mappings ())
61 const TyTy::BaseType
*arg
= c
.get_tyty ();
64 const TyTy::BaseType
*p
= arg
->get_root ();
65 constrained_symbols
.insert (p
->get_ty_ref ());
68 for (const auto &c
: constraint_b
.get_mappings ())
70 const TyTy::BaseType
*arg
= c
.get_tyty ();
73 const TyTy::BaseType
*p
= arg
->get_root ();
74 constrained_symbols
.insert (p
->get_ty_ref ());
78 const auto root
= reference
->get_root ();
79 if (root
->get_kind () == TyTy::TypeKind::PARAM
)
81 const TyTy::ParamType
*p
= static_cast<const TyTy::ParamType
*> (root
);
82 constrained_symbols
.insert (p
->get_ty_ref ());
85 // check for unconstrained
86 bool unconstrained
= false;
87 for (auto &sym
: symbols_to_constrain
)
89 bool used
= constrained_symbols
.find (sym
) != constrained_symbols
.end ();
92 location_t locus
= symbol_to_location
.at (sym
);
93 rust_error_at (locus
, "unconstrained type parameter");
98 context
->insert_unconstrained_check_marker (reference
->get_ref (),
101 return unconstrained
;
105 TypeCheckBase::resolve_literal (const Analysis::NodeMapping
&expr_mappings
,
106 HIR::Literal
&literal
, location_t locus
)
108 TyTy::BaseType
*infered
= nullptr;
109 switch (literal
.get_lit_type ())
111 case HIR::Literal::LitType::INT
: {
114 switch (literal
.get_type_hint ())
117 ok
= context
->lookup_builtin ("i8", &infered
);
120 ok
= context
->lookup_builtin ("i16", &infered
);
123 ok
= context
->lookup_builtin ("i32", &infered
);
126 ok
= context
->lookup_builtin ("i64", &infered
);
129 ok
= context
->lookup_builtin ("i128", &infered
);
133 ok
= context
->lookup_builtin ("u8", &infered
);
136 ok
= context
->lookup_builtin ("u16", &infered
);
139 ok
= context
->lookup_builtin ("u32", &infered
);
142 ok
= context
->lookup_builtin ("u64", &infered
);
145 ok
= context
->lookup_builtin ("u128", &infered
);
149 literal
.set_lit_type (HIR::Literal::LitType::FLOAT
);
150 ok
= context
->lookup_builtin ("f32", &infered
);
153 literal
.set_lit_type (HIR::Literal::LitType::FLOAT
);
154 ok
= context
->lookup_builtin ("f64", &infered
);
158 ok
= context
->lookup_builtin ("isize", &infered
);
162 ok
= context
->lookup_builtin ("usize", &infered
);
168 = new TyTy::InferType (expr_mappings
.get_hirid (),
169 TyTy::InferType::InferTypeKind::INTEGRAL
,
170 TyTy::InferType::TypeHint::Default (),
178 case HIR::Literal::LitType::FLOAT
: {
181 switch (literal
.get_type_hint ())
184 ok
= context
->lookup_builtin ("f32", &infered
);
187 ok
= context
->lookup_builtin ("f64", &infered
);
193 = new TyTy::InferType (expr_mappings
.get_hirid (),
194 TyTy::InferType::InferTypeKind::FLOAT
,
195 TyTy::InferType::TypeHint::Default (),
203 case HIR::Literal::LitType::BOOL
: {
204 auto ok
= context
->lookup_builtin ("bool", &infered
);
209 case HIR::Literal::LitType::CHAR
: {
210 auto ok
= context
->lookup_builtin ("char", &infered
);
215 case HIR::Literal::LitType::BYTE
: {
216 auto ok
= context
->lookup_builtin ("u8", &infered
);
221 case HIR::Literal::LitType::STRING
: {
222 TyTy::BaseType
*base
= nullptr;
223 auto ok
= context
->lookup_builtin ("str", &base
);
226 infered
= new TyTy::ReferenceType (expr_mappings
.get_hirid (),
227 TyTy::TyVar (base
->get_ref ()),
229 TyTy::Region::make_static ());
233 case HIR::Literal::LitType::BYTE_STRING
: {
234 /* This is an arraytype of u8 reference (&[u8;size]). It isn't in
235 UTF-8, but really just a byte array. Code to construct the array
236 reference copied from ArrayElemsValues and ArrayType. */
238 auto ok
= context
->lookup_builtin ("u8", &u8
);
241 auto crate_num
= mappings
->get_current_crate ();
242 Analysis::NodeMapping
capacity_mapping (crate_num
, UNKNOWN_NODEID
,
243 mappings
->get_next_hir_id (
245 UNKNOWN_LOCAL_DEFID
);
247 /* Capacity is the size of the string (number of chars).
248 It is a constant, but for fold it to get a tree. */
249 std::string capacity_str
250 = std::to_string (literal
.as_string ().size ());
251 HIR::LiteralExpr
*literal_capacity
252 = new HIR::LiteralExpr (capacity_mapping
, capacity_str
,
253 HIR::Literal::LitType::INT
,
254 PrimitiveCoreType::CORETYPE_USIZE
, locus
, {});
256 // mark the type for this implicit node
257 TyTy::BaseType
*expected_ty
= nullptr;
258 ok
= context
->lookup_builtin ("usize", &expected_ty
);
260 context
->insert_type (capacity_mapping
, expected_ty
);
262 Analysis::NodeMapping
array_mapping (crate_num
, UNKNOWN_NODEID
,
263 mappings
->get_next_hir_id (
265 UNKNOWN_LOCAL_DEFID
);
267 TyTy::ArrayType
*array
268 = new TyTy::ArrayType (array_mapping
.get_hirid (), locus
,
270 TyTy::TyVar (u8
->get_ref ()));
271 context
->insert_type (array_mapping
, array
);
273 infered
= new TyTy::ReferenceType (expr_mappings
.get_hirid (),
274 TyTy::TyVar (array
->get_ref ()),
276 TyTy::Region::make_static ());
288 TyTy::ADTType::ReprOptions
289 TypeCheckBase::parse_repr_options (const AST::AttrVec
&attrs
, location_t locus
)
291 TyTy::ADTType::ReprOptions repr
;
295 for (const auto &attr
: attrs
)
297 bool is_repr
= attr
.get_path ().as_string () == Values::Attributes::REPR
;
300 const AST::AttrInput
&input
= attr
.get_attr_input ();
301 bool is_token_tree
= input
.get_attr_input_type ()
302 == AST::AttrInput::AttrInputType::TOKEN_TREE
;
303 rust_assert (is_token_tree
);
304 const auto &option
= static_cast<const AST::DelimTokenTree
&> (input
);
305 AST::AttrInputMetaItemContainer
*meta_items
306 = option
.parse_to_meta_item ();
308 const std::string inline_option
309 = meta_items
->get_items ().at (0)->as_string ();
311 // TODO: it would probably be better to make the MetaItems more aware
312 // of constructs with nesting like #[repr(packed(2))] rather than
313 // manually parsing the string "packed(2)" here.
315 size_t oparen
= inline_option
.find ('(', 0);
316 bool is_pack
= false, is_align
= false;
317 unsigned char value
= 1;
319 if (oparen
== std::string::npos
)
321 is_pack
= inline_option
.compare ("packed") == 0;
322 is_align
= inline_option
.compare ("align") == 0;
327 std::string rep
= inline_option
.substr (0, oparen
);
328 is_pack
= rep
.compare ("packed") == 0;
329 is_align
= rep
.compare ("align") == 0;
331 size_t cparen
= inline_option
.find (')', oparen
);
332 if (cparen
== std::string::npos
)
334 rust_error_at (locus
, "malformed attribute");
337 std::string value_str
= inline_option
.substr (oparen
, cparen
);
338 value
= strtoul (value_str
.c_str () + 1, NULL
, 10);
346 // Multiple repr options must be specified with e.g. #[repr(C,
356 TypeCheckBase::resolve_generic_params (
357 const std::vector
<std::unique_ptr
<HIR::GenericParam
>> &generic_params
,
358 std::vector
<TyTy::SubstitutionParamMapping
> &substitutions
)
360 for (auto &generic_param
: generic_params
)
362 switch (generic_param
->get_kind ())
364 case HIR::GenericParam::GenericKind::LIFETIME
: {
366 = static_cast<HIR::LifetimeParam
&> (*generic_param
);
367 auto lifetime
= lifetime_param
.get_lifetime ();
368 rust_assert (lifetime
.get_lifetime_type ()
369 == AST::Lifetime::LifetimeType::NAMED
);
370 context
->get_lifetime_resolver ().insert_mapping (
371 context
->intern_lifetime (lifetime
));
376 case HIR::GenericParam::GenericKind::CONST
: {
378 = static_cast<HIR::ConstGenericParam
*> (generic_param
.get ());
380 = TypeCheckType::Resolve (param
->get_type ().get ());
382 if (param
->has_default_expression ())
384 auto expr_type
= TypeCheckExpr::Resolve (
385 param
->get_default_expression ().get ());
388 param
->get_mappings ().get_hirid (),
389 TyTy::TyWithLocation (specified_type
),
390 TyTy::TyWithLocation (
391 expr_type
, param
->get_default_expression ()->get_locus ()),
392 param
->get_locus ());
395 context
->insert_type (generic_param
->get_mappings (),
400 case HIR::GenericParam::GenericKind::TYPE
: {
402 = TypeResolveGenericParam::Resolve (generic_param
.get ());
403 context
->insert_type (generic_param
->get_mappings (), param_type
);
405 substitutions
.push_back (TyTy::SubstitutionParamMapping (
406 static_cast<HIR::TypeParam
&> (*generic_param
), param_type
));
413 TyTy::TypeBoundPredicate
414 TypeCheckBase::get_marker_predicate (LangItem::Kind item_type
, location_t locus
)
416 DefId item_id
= mappings
->get_lang_item (item_type
, locus
);
417 HIR::Item
*item
= mappings
->lookup_defid (item_id
);
418 rust_assert (item
!= nullptr);
419 rust_assert (item
->get_item_kind () == HIR::Item::ItemKind::Trait
);
421 HIR::Trait
&trait
= *static_cast<HIR::Trait
*> (item
);
422 TraitReference
*ref
= TraitResolver::Resolve (trait
);
423 rust_assert (ref
!= nullptr);
425 return TyTy::TypeBoundPredicate (*ref
, BoundPolarity::RegularBound
, locus
);
428 } // namespace Resolver