Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : : #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"
25 : :
26 : : namespace Rust {
27 : : namespace Resolver {
28 : :
29 : 292943 : TypeCheckBase::TypeCheckBase ()
30 : 292943 : : mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),
31 : 585886 : context (TypeCheckContext::get ())
32 : 292943 : {}
33 : :
34 : : bool
35 : 11982 : 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)
40 : : {
41 : 11982 : bool check_result = false;
42 : 11982 : bool check_completed
43 : 11982 : = context->have_checked_for_unconstrained (reference->get_ref (),
44 : : &check_result);
45 : 11982 : if (check_completed)
46 : 8926 : return check_result;
47 : :
48 : 3056 : std::set<HirId> symbols_to_constrain;
49 : 3056 : std::map<HirId, location_t> symbol_to_location;
50 : 3759 : for (const auto &p : params_to_constrain)
51 : : {
52 : 703 : HirId ref = p.get_param_ty ()->get_ref ();
53 : 703 : symbols_to_constrain.insert (ref);
54 : 703 : symbol_to_location.insert ({ref, p.get_param_locus ()});
55 : : }
56 : :
57 : : // set up the set of constrained symbols
58 : 3056 : std::set<HirId> constrained_symbols;
59 : 5803 : for (const auto &c : constraint_a.get_mappings ())
60 : : {
61 : 2747 : const TyTy::BaseType *arg = c.get_tyty ();
62 : 2747 : if (arg != nullptr)
63 : : {
64 : 2747 : const TyTy::BaseType *p = arg->get_root ();
65 : 2747 : constrained_symbols.insert (p->get_ty_ref ());
66 : : }
67 : : }
68 : 3457 : for (const auto &c : constraint_b.get_mappings ())
69 : : {
70 : 401 : const TyTy::BaseType *arg = c.get_tyty ();
71 : 401 : if (arg != nullptr)
72 : : {
73 : 401 : const TyTy::BaseType *p = arg->get_root ();
74 : 401 : constrained_symbols.insert (p->get_ty_ref ());
75 : : }
76 : : }
77 : :
78 : 3056 : const auto root = reference->get_root ();
79 : 3056 : if (root->get_kind () == TyTy::TypeKind::PARAM)
80 : : {
81 : 371 : const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
82 : 371 : constrained_symbols.insert (p->get_ty_ref ());
83 : : }
84 : :
85 : : // check for unconstrained
86 : 3056 : bool unconstrained = false;
87 : 3759 : for (auto &sym : symbols_to_constrain)
88 : : {
89 : 703 : bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
90 : 703 : if (!used)
91 : : {
92 : 2 : location_t locus = symbol_to_location.at (sym);
93 : 2 : rust_error_at (locus, "unconstrained type parameter");
94 : 2 : unconstrained = true;
95 : : }
96 : : }
97 : :
98 : 3056 : context->insert_unconstrained_check_marker (reference->get_ref (),
99 : : unconstrained);
100 : :
101 : 3056 : return unconstrained;
102 : 3056 : }
103 : :
104 : : TyTy::BaseType *
105 : 13159 : TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
106 : : HIR::Literal &literal, location_t locus)
107 : : {
108 : 13159 : TyTy::BaseType *infered = nullptr;
109 : 13159 : switch (literal.get_lit_type ())
110 : : {
111 : 10422 : case HIR::Literal::LitType::INT: {
112 : 10422 : bool ok = false;
113 : :
114 : 10422 : switch (literal.get_type_hint ())
115 : : {
116 : 22 : case CORETYPE_I8:
117 : 22 : ok = context->lookup_builtin ("i8", &infered);
118 : 22 : break;
119 : 14 : case CORETYPE_I16:
120 : 14 : ok = context->lookup_builtin ("i16", &infered);
121 : 14 : break;
122 : 80 : case CORETYPE_I32:
123 : 80 : ok = context->lookup_builtin ("i32", &infered);
124 : 80 : break;
125 : 14 : case CORETYPE_I64:
126 : 14 : ok = context->lookup_builtin ("i64", &infered);
127 : 14 : break;
128 : 14 : case CORETYPE_I128:
129 : 14 : ok = context->lookup_builtin ("i128", &infered);
130 : 14 : break;
131 : :
132 : 27 : case CORETYPE_U8:
133 : 27 : ok = context->lookup_builtin ("u8", &infered);
134 : 27 : break;
135 : 23 : case CORETYPE_U16:
136 : 23 : ok = context->lookup_builtin ("u16", &infered);
137 : 23 : break;
138 : 86 : case CORETYPE_U32:
139 : 86 : ok = context->lookup_builtin ("u32", &infered);
140 : 86 : break;
141 : 14 : case CORETYPE_U64:
142 : 14 : ok = context->lookup_builtin ("u64", &infered);
143 : 14 : break;
144 : 14 : case CORETYPE_U128:
145 : 14 : ok = context->lookup_builtin ("u128", &infered);
146 : 14 : break;
147 : :
148 : 465 : case CORETYPE_F32:
149 : 465 : literal.set_lit_type (HIR::Literal::LitType::FLOAT);
150 : 465 : ok = context->lookup_builtin ("f32", &infered);
151 : 465 : break;
152 : 205 : case CORETYPE_F64:
153 : 205 : literal.set_lit_type (HIR::Literal::LitType::FLOAT);
154 : 205 : ok = context->lookup_builtin ("f64", &infered);
155 : 205 : break;
156 : :
157 : 2 : case CORETYPE_ISIZE:
158 : 2 : ok = context->lookup_builtin ("isize", &infered);
159 : 2 : break;
160 : :
161 : 2 : case CORETYPE_USIZE:
162 : 2 : ok = context->lookup_builtin ("usize", &infered);
163 : 2 : break;
164 : :
165 : 9440 : default:
166 : 9440 : ok = true;
167 : 9440 : infered
168 : 9440 : = new TyTy::InferType (expr_mappings.get_hirid (),
169 : : TyTy::InferType::InferTypeKind::INTEGRAL,
170 : : TyTy::InferType::TypeHint::Default (),
171 : 9440 : locus);
172 : 9440 : break;
173 : : }
174 : 10422 : rust_assert (ok);
175 : : }
176 : : break;
177 : :
178 : 312 : case HIR::Literal::LitType::FLOAT: {
179 : 312 : bool ok = false;
180 : :
181 : 312 : switch (literal.get_type_hint ())
182 : : {
183 : 22 : case CORETYPE_F32:
184 : 22 : ok = context->lookup_builtin ("f32", &infered);
185 : 22 : break;
186 : 14 : case CORETYPE_F64:
187 : 14 : ok = context->lookup_builtin ("f64", &infered);
188 : 14 : break;
189 : :
190 : 276 : default:
191 : 276 : ok = true;
192 : 276 : infered
193 : 276 : = new TyTy::InferType (expr_mappings.get_hirid (),
194 : : TyTy::InferType::InferTypeKind::FLOAT,
195 : : TyTy::InferType::TypeHint::Default (),
196 : 276 : locus);
197 : 276 : break;
198 : : }
199 : 312 : rust_assert (ok);
200 : : }
201 : : break;
202 : :
203 : 655 : case HIR::Literal::LitType::BOOL: {
204 : 655 : auto ok = context->lookup_builtin ("bool", &infered);
205 : 655 : rust_assert (ok);
206 : : }
207 : : break;
208 : :
209 : 186 : case HIR::Literal::LitType::CHAR: {
210 : 186 : auto ok = context->lookup_builtin ("char", &infered);
211 : 186 : rust_assert (ok);
212 : : }
213 : : break;
214 : :
215 : 184 : case HIR::Literal::LitType::BYTE: {
216 : 184 : auto ok = context->lookup_builtin ("u8", &infered);
217 : 184 : rust_assert (ok);
218 : : }
219 : : break;
220 : :
221 : 1372 : case HIR::Literal::LitType::STRING: {
222 : 1372 : TyTy::BaseType *base = nullptr;
223 : 1372 : auto ok = context->lookup_builtin ("str", &base);
224 : 1372 : rust_assert (ok);
225 : :
226 : 2744 : infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
227 : 1372 : TyTy::TyVar (base->get_ref ()),
228 : : Mutability::Imm,
229 : 2744 : TyTy::Region::make_static ());
230 : : }
231 : 1372 : break;
232 : :
233 : 28 : 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 : 28 : TyTy::BaseType *u8;
238 : 28 : auto ok = context->lookup_builtin ("u8", &u8);
239 : 28 : rust_assert (ok);
240 : :
241 : 28 : auto crate_num = mappings->get_current_crate ();
242 : 28 : Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
243 : 28 : mappings->get_next_hir_id (
244 : : crate_num),
245 : 28 : UNKNOWN_LOCAL_DEFID);
246 : :
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 : 28 : std::string capacity_str
250 : 28 : = std::to_string (literal.as_string ().size ());
251 : 28 : HIR::LiteralExpr *literal_capacity
252 : : = new HIR::LiteralExpr (capacity_mapping, capacity_str,
253 : : HIR::Literal::LitType::INT,
254 : 28 : PrimitiveCoreType::CORETYPE_USIZE, locus, {});
255 : :
256 : : // mark the type for this implicit node
257 : 28 : TyTy::BaseType *expected_ty = nullptr;
258 : 28 : ok = context->lookup_builtin ("usize", &expected_ty);
259 : 28 : rust_assert (ok);
260 : 28 : context->insert_type (capacity_mapping, expected_ty);
261 : :
262 : 28 : Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
263 : 28 : mappings->get_next_hir_id (
264 : : crate_num),
265 : 28 : UNKNOWN_LOCAL_DEFID);
266 : :
267 : 28 : TyTy::ArrayType *array
268 : : = new TyTy::ArrayType (array_mapping.get_hirid (), locus,
269 : : *literal_capacity,
270 : 28 : TyTy::TyVar (u8->get_ref ()));
271 : 28 : context->insert_type (array_mapping, array);
272 : :
273 : 56 : infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
274 : 28 : TyTy::TyVar (array->get_ref ()),
275 : : Mutability::Imm,
276 : 56 : TyTy::Region::make_static ());
277 : 28 : }
278 : 28 : break;
279 : :
280 : 0 : default:
281 : 0 : rust_unreachable ();
282 : 13159 : break;
283 : : }
284 : :
285 : 13159 : return infered;
286 : : }
287 : :
288 : : TyTy::ADTType::ReprOptions
289 : 1674 : TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
290 : : {
291 : 1674 : TyTy::ADTType::ReprOptions repr;
292 : 1674 : repr.pack = 0;
293 : 1674 : repr.align = 0;
294 : :
295 : 1809 : for (const auto &attr : attrs)
296 : : {
297 : 143 : bool is_repr = attr.get_path ().as_string () == Values::Attributes::REPR;
298 : 143 : if (is_repr)
299 : : {
300 : 8 : const AST::AttrInput &input = attr.get_attr_input ();
301 : 8 : bool is_token_tree = input.get_attr_input_type ()
302 : 8 : == AST::AttrInput::AttrInputType::TOKEN_TREE;
303 : 8 : rust_assert (is_token_tree);
304 : 8 : const auto &option = static_cast<const AST::DelimTokenTree &> (input);
305 : 8 : AST::AttrInputMetaItemContainer *meta_items
306 : 8 : = option.parse_to_meta_item ();
307 : :
308 : 8 : const std::string inline_option
309 : 8 : = meta_items->get_items ().at (0)->as_string ();
310 : :
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.
314 : :
315 : 8 : size_t oparen = inline_option.find ('(', 0);
316 : 8 : bool is_pack = false, is_align = false;
317 : 8 : unsigned char value = 1;
318 : :
319 : 8 : if (oparen == std::string::npos)
320 : : {
321 : 2 : is_pack = inline_option.compare ("packed") == 0;
322 : 2 : is_align = inline_option.compare ("align") == 0;
323 : : }
324 : :
325 : : else
326 : : {
327 : 6 : std::string rep = inline_option.substr (0, oparen);
328 : 6 : is_pack = rep.compare ("packed") == 0;
329 : 6 : is_align = rep.compare ("align") == 0;
330 : :
331 : 6 : size_t cparen = inline_option.find (')', oparen);
332 : 6 : if (cparen == std::string::npos)
333 : : {
334 : 0 : rust_error_at (locus, "malformed attribute");
335 : : }
336 : :
337 : 6 : std::string value_str = inline_option.substr (oparen, cparen);
338 : 6 : value = strtoul (value_str.c_str () + 1, NULL, 10);
339 : 6 : }
340 : :
341 : 8 : if (is_pack)
342 : : repr.pack = value;
343 : 4 : else if (is_align)
344 : 4 : repr.align = value;
345 : :
346 : : // Multiple repr options must be specified with e.g. #[repr(C,
347 : : // packed(2))].
348 : 8 : break;
349 : 8 : }
350 : : }
351 : :
352 : 1674 : return repr;
353 : : }
354 : :
355 : : void
356 : 5589 : TypeCheckBase::resolve_generic_params (
357 : : const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
358 : : std::vector<TyTy::SubstitutionParamMapping> &substitutions)
359 : : {
360 : 11907 : for (auto &generic_param : generic_params)
361 : : {
362 : 6318 : switch (generic_param->get_kind ())
363 : : {
364 : 822 : case HIR::GenericParam::GenericKind::LIFETIME: {
365 : 822 : auto lifetime_param
366 : 822 : = static_cast<HIR::LifetimeParam &> (*generic_param);
367 : 822 : auto lifetime = lifetime_param.get_lifetime ();
368 : 822 : rust_assert (lifetime.get_lifetime_type ()
369 : : == AST::Lifetime::LifetimeType::NAMED);
370 : 822 : context->get_lifetime_resolver ().insert_mapping (
371 : : context->intern_lifetime (lifetime));
372 : 822 : }
373 : :
374 : 822 : break;
375 : :
376 : 14 : case HIR::GenericParam::GenericKind::CONST: {
377 : 14 : auto param
378 : 14 : = static_cast<HIR::ConstGenericParam *> (generic_param.get ());
379 : 14 : auto specified_type
380 : 14 : = TypeCheckType::Resolve (param->get_type ().get ());
381 : :
382 : 14 : if (param->has_default_expression ())
383 : : {
384 : 10 : auto expr_type = TypeCheckExpr::Resolve (
385 : 10 : param->get_default_expression ().get ());
386 : :
387 : 20 : coercion_site (
388 : 20 : param->get_mappings ().get_hirid (),
389 : 10 : TyTy::TyWithLocation (specified_type),
390 : : TyTy::TyWithLocation (
391 : 10 : expr_type, param->get_default_expression ()->get_locus ()),
392 : : param->get_locus ());
393 : : }
394 : :
395 : 14 : context->insert_type (generic_param->get_mappings (),
396 : : specified_type);
397 : : }
398 : 14 : break;
399 : :
400 : 5482 : case HIR::GenericParam::GenericKind::TYPE: {
401 : 5482 : auto param_type
402 : 5482 : = TypeResolveGenericParam::Resolve (generic_param.get ());
403 : 5482 : context->insert_type (generic_param->get_mappings (), param_type);
404 : :
405 : 5482 : substitutions.push_back (TyTy::SubstitutionParamMapping (
406 : 5482 : static_cast<HIR::TypeParam &> (*generic_param), param_type));
407 : : }
408 : 5482 : break;
409 : : }
410 : : }
411 : 5589 : }
412 : :
413 : : TyTy::TypeBoundPredicate
414 : 6352 : TypeCheckBase::get_marker_predicate (LangItem::Kind item_type, location_t locus)
415 : : {
416 : 6352 : DefId item_id = mappings->get_lang_item (item_type, locus);
417 : 6350 : HIR::Item *item = mappings->lookup_defid (item_id);
418 : 6350 : rust_assert (item != nullptr);
419 : 6350 : rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
420 : :
421 : 6350 : HIR::Trait &trait = *static_cast<HIR::Trait *> (item);
422 : 6350 : TraitReference *ref = TraitResolver::Resolve (trait);
423 : 6350 : rust_assert (ref != nullptr);
424 : :
425 : 6350 : return TyTy::TypeBoundPredicate (*ref, BoundPolarity::RegularBound, locus);
426 : : }
427 : :
428 : : } // namespace Resolver
429 : : } // namespace Rust
|