[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check-base.cc
blobd65447b5ffde6e5507bd1f1702ea3bca348f9bbe
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
8 // version.
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.
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"
26 namespace Rust {
27 namespace Resolver {
29 TypeCheckBase::TypeCheckBase ()
30 : mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
31 context (TypeCheckContext::get ())
34 bool
35 TypeCheckBase::check_for_unconstrained (
36 const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
37 const TyTy::SubstitutionArgumentMappings &constraint_a,
38 const TyTy::SubstitutionArgumentMappings &constraint_b,
39 const TyTy::BaseType *reference)
41 bool check_result = false;
42 bool check_completed
43 = context->have_checked_for_unconstrained (reference->get_ref (),
44 &check_result);
45 if (check_completed)
46 return check_result;
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 ();
62 if (arg != nullptr)
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 ();
71 if (arg != nullptr)
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 ();
90 if (!used)
92 location_t locus = symbol_to_location.at (sym);
93 rust_error_at (locus, "unconstrained type parameter");
94 unconstrained = true;
98 context->insert_unconstrained_check_marker (reference->get_ref (),
99 unconstrained);
101 return unconstrained;
104 TyTy::BaseType *
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: {
112 bool ok = false;
114 switch (literal.get_type_hint ())
116 case CORETYPE_I8:
117 ok = context->lookup_builtin ("i8", &infered);
118 break;
119 case CORETYPE_I16:
120 ok = context->lookup_builtin ("i16", &infered);
121 break;
122 case CORETYPE_I32:
123 ok = context->lookup_builtin ("i32", &infered);
124 break;
125 case CORETYPE_I64:
126 ok = context->lookup_builtin ("i64", &infered);
127 break;
128 case CORETYPE_I128:
129 ok = context->lookup_builtin ("i128", &infered);
130 break;
132 case CORETYPE_U8:
133 ok = context->lookup_builtin ("u8", &infered);
134 break;
135 case CORETYPE_U16:
136 ok = context->lookup_builtin ("u16", &infered);
137 break;
138 case CORETYPE_U32:
139 ok = context->lookup_builtin ("u32", &infered);
140 break;
141 case CORETYPE_U64:
142 ok = context->lookup_builtin ("u64", &infered);
143 break;
144 case CORETYPE_U128:
145 ok = context->lookup_builtin ("u128", &infered);
146 break;
148 case CORETYPE_F32:
149 literal.set_lit_type (HIR::Literal::LitType::FLOAT);
150 ok = context->lookup_builtin ("f32", &infered);
151 break;
152 case CORETYPE_F64:
153 literal.set_lit_type (HIR::Literal::LitType::FLOAT);
154 ok = context->lookup_builtin ("f64", &infered);
155 break;
157 case CORETYPE_ISIZE:
158 ok = context->lookup_builtin ("isize", &infered);
159 break;
161 case CORETYPE_USIZE:
162 ok = context->lookup_builtin ("usize", &infered);
163 break;
165 default:
166 ok = true;
167 infered
168 = new TyTy::InferType (expr_mappings.get_hirid (),
169 TyTy::InferType::InferTypeKind::INTEGRAL,
170 TyTy::InferType::TypeHint::Default (),
171 locus);
172 break;
174 rust_assert (ok);
176 break;
178 case HIR::Literal::LitType::FLOAT: {
179 bool ok = false;
181 switch (literal.get_type_hint ())
183 case CORETYPE_F32:
184 ok = context->lookup_builtin ("f32", &infered);
185 break;
186 case CORETYPE_F64:
187 ok = context->lookup_builtin ("f64", &infered);
188 break;
190 default:
191 ok = true;
192 infered
193 = new TyTy::InferType (expr_mappings.get_hirid (),
194 TyTy::InferType::InferTypeKind::FLOAT,
195 TyTy::InferType::TypeHint::Default (),
196 locus);
197 break;
199 rust_assert (ok);
201 break;
203 case HIR::Literal::LitType::BOOL: {
204 auto ok = context->lookup_builtin ("bool", &infered);
205 rust_assert (ok);
207 break;
209 case HIR::Literal::LitType::CHAR: {
210 auto ok = context->lookup_builtin ("char", &infered);
211 rust_assert (ok);
213 break;
215 case HIR::Literal::LitType::BYTE: {
216 auto ok = context->lookup_builtin ("u8", &infered);
217 rust_assert (ok);
219 break;
221 case HIR::Literal::LitType::STRING: {
222 TyTy::BaseType *base = nullptr;
223 auto ok = context->lookup_builtin ("str", &base);
224 rust_assert (ok);
226 infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
227 TyTy::TyVar (base->get_ref ()),
228 Mutability::Imm,
229 TyTy::Region::make_static ());
231 break;
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. */
237 TyTy::BaseType *u8;
238 auto ok = context->lookup_builtin ("u8", &u8);
239 rust_assert (ok);
241 auto crate_num = mappings->get_current_crate ();
242 Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
243 mappings->get_next_hir_id (
244 crate_num),
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);
259 rust_assert (ok);
260 context->insert_type (capacity_mapping, expected_ty);
262 Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
263 mappings->get_next_hir_id (
264 crate_num),
265 UNKNOWN_LOCAL_DEFID);
267 TyTy::ArrayType *array
268 = new TyTy::ArrayType (array_mapping.get_hirid (), locus,
269 *literal_capacity,
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 ()),
275 Mutability::Imm,
276 TyTy::Region::make_static ());
278 break;
280 default:
281 rust_unreachable ();
282 break;
285 return infered;
288 TyTy::ADTType::ReprOptions
289 TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
291 TyTy::ADTType::ReprOptions repr;
292 repr.pack = 0;
293 repr.align = 0;
295 for (const auto &attr : attrs)
297 bool is_repr = attr.get_path ().as_string () == Values::Attributes::REPR;
298 if (is_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;
325 else
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);
341 if (is_pack)
342 repr.pack = value;
343 else if (is_align)
344 repr.align = value;
346 // Multiple repr options must be specified with e.g. #[repr(C,
347 // packed(2))].
348 break;
352 return repr;
355 void
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: {
365 auto lifetime_param
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));
374 break;
376 case HIR::GenericParam::GenericKind::CONST: {
377 auto param
378 = static_cast<HIR::ConstGenericParam *> (generic_param.get ());
379 auto specified_type
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 ());
387 coercion_site (
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 (),
396 specified_type);
398 break;
400 case HIR::GenericParam::GenericKind::TYPE: {
401 auto param_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));
408 break;
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
429 } // namespace Rust