]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-hir-type-check-base.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / typecheck / rust-hir-type-check-base.cc
CommitLineData
83ffe9cd 1// Copyright (C) 2020-2023 Free Software Foundation, Inc.
c6c3db21
PH
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-type.h"
21#include "rust-hir-type-check-expr.h"
22#include "rust-coercion.h"
23#include "rust-casts.h"
24
25namespace Rust {
26namespace Resolver {
27
28bool
29TypeCheckBase::check_for_unconstrained (
30 const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
31 const TyTy::SubstitutionArgumentMappings &constraint_a,
32 const TyTy::SubstitutionArgumentMappings &constraint_b,
33 const TyTy::BaseType *reference)
34{
35 std::set<HirId> symbols_to_constrain;
36 std::map<HirId, Location> symbol_to_location;
37 for (const auto &p : params_to_constrain)
38 {
39 HirId ref = p.get_param_ty ()->get_ref ();
40 symbols_to_constrain.insert (ref);
41 symbol_to_location.insert ({ref, p.get_param_locus ()});
42 }
43
44 // set up the set of constrained symbols
45 std::set<HirId> constrained_symbols;
46 for (const auto &c : constraint_a.get_mappings ())
47 {
48 const TyTy::BaseType *arg = c.get_tyty ();
49 if (arg != nullptr)
50 {
51 const TyTy::BaseType *p = arg->get_root ();
52 constrained_symbols.insert (p->get_ty_ref ());
53 }
54 }
55 for (const auto &c : constraint_b.get_mappings ())
56 {
57 const TyTy::BaseType *arg = c.get_tyty ();
58 if (arg != nullptr)
59 {
60 const TyTy::BaseType *p = arg->get_root ();
61 constrained_symbols.insert (p->get_ty_ref ());
62 }
63 }
64
65 const auto root = reference->get_root ();
66 if (root->get_kind () == TyTy::TypeKind::PARAM)
67 {
68 const TyTy::ParamType *p = static_cast<const TyTy::ParamType *> (root);
69 constrained_symbols.insert (p->get_ty_ref ());
70 }
71
72 // check for unconstrained
73 bool unconstrained = false;
74 for (auto &sym : symbols_to_constrain)
75 {
76 bool used = constrained_symbols.find (sym) != constrained_symbols.end ();
77 if (!used)
78 {
79 Location locus = symbol_to_location.at (sym);
80 rust_error_at (locus, "unconstrained type parameter");
81 unconstrained = true;
82 }
83 }
84 return unconstrained;
85}
86
87TyTy::BaseType *
88TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
89 HIR::Literal &literal, Location locus)
90{
91 TyTy::BaseType *infered = nullptr;
92 switch (literal.get_lit_type ())
93 {
94 case HIR::Literal::LitType::INT: {
95 bool ok = false;
96
97 switch (literal.get_type_hint ())
98 {
99 case CORETYPE_I8:
100 ok = context->lookup_builtin ("i8", &infered);
101 break;
102 case CORETYPE_I16:
103 ok = context->lookup_builtin ("i16", &infered);
104 break;
105 case CORETYPE_I32:
106 ok = context->lookup_builtin ("i32", &infered);
107 break;
108 case CORETYPE_I64:
109 ok = context->lookup_builtin ("i64", &infered);
110 break;
111 case CORETYPE_I128:
112 ok = context->lookup_builtin ("i128", &infered);
113 break;
114
115 case CORETYPE_U8:
116 ok = context->lookup_builtin ("u8", &infered);
117 break;
118 case CORETYPE_U16:
119 ok = context->lookup_builtin ("u16", &infered);
120 break;
121 case CORETYPE_U32:
122 ok = context->lookup_builtin ("u32", &infered);
123 break;
124 case CORETYPE_U64:
125 ok = context->lookup_builtin ("u64", &infered);
126 break;
127 case CORETYPE_U128:
128 ok = context->lookup_builtin ("u128", &infered);
129 break;
130
131 case CORETYPE_F32:
132 literal.set_lit_type (HIR::Literal::LitType::FLOAT);
133 ok = context->lookup_builtin ("f32", &infered);
134 break;
135 case CORETYPE_F64:
136 literal.set_lit_type (HIR::Literal::LitType::FLOAT);
137 ok = context->lookup_builtin ("f64", &infered);
138 break;
139
140 case CORETYPE_ISIZE:
141 ok = context->lookup_builtin ("isize", &infered);
142 break;
143
144 case CORETYPE_USIZE:
145 ok = context->lookup_builtin ("usize", &infered);
146 break;
147
148 default:
149 ok = true;
150 infered
151 = new TyTy::InferType (expr_mappings.get_hirid (),
152 TyTy::InferType::InferTypeKind::INTEGRAL,
153 locus);
154 break;
155 }
156 rust_assert (ok);
157 }
158 break;
159
160 case HIR::Literal::LitType::FLOAT: {
161 bool ok = false;
162
163 switch (literal.get_type_hint ())
164 {
165 case CORETYPE_F32:
166 ok = context->lookup_builtin ("f32", &infered);
167 break;
168 case CORETYPE_F64:
169 ok = context->lookup_builtin ("f64", &infered);
170 break;
171
172 default:
173 ok = true;
174 infered
175 = new TyTy::InferType (expr_mappings.get_hirid (),
176 TyTy::InferType::InferTypeKind::FLOAT,
177 locus);
178 break;
179 }
180 rust_assert (ok);
181 }
182 break;
183
184 case HIR::Literal::LitType::BOOL: {
185 auto ok = context->lookup_builtin ("bool", &infered);
186 rust_assert (ok);
187 }
188 break;
189
190 case HIR::Literal::LitType::CHAR: {
191 auto ok = context->lookup_builtin ("char", &infered);
192 rust_assert (ok);
193 }
194 break;
195
196 case HIR::Literal::LitType::BYTE: {
197 auto ok = context->lookup_builtin ("u8", &infered);
198 rust_assert (ok);
199 }
200 break;
201
202 case HIR::Literal::LitType::STRING: {
203 TyTy::BaseType *base = nullptr;
204 auto ok = context->lookup_builtin ("str", &base);
205 rust_assert (ok);
206
207 infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
208 TyTy::TyVar (base->get_ref ()),
209 Mutability::Imm);
210 }
211 break;
212
213 case HIR::Literal::LitType::BYTE_STRING: {
214 /* This is an arraytype of u8 reference (&[u8;size]). It isn't in
215 UTF-8, but really just a byte array. Code to construct the array
216 reference copied from ArrayElemsValues and ArrayType. */
217 TyTy::BaseType *u8;
218 auto ok = context->lookup_builtin ("u8", &u8);
219 rust_assert (ok);
220
221 auto crate_num = mappings->get_current_crate ();
222 Analysis::NodeMapping capacity_mapping (crate_num, UNKNOWN_NODEID,
223 mappings->get_next_hir_id (
224 crate_num),
225 UNKNOWN_LOCAL_DEFID);
226
227 /* Capacity is the size of the string (number of chars).
228 It is a constant, but for fold it to get a tree. */
229 std::string capacity_str
230 = std::to_string (literal.as_string ().size ());
231 HIR::LiteralExpr *literal_capacity
232 = new HIR::LiteralExpr (capacity_mapping, capacity_str,
233 HIR::Literal::LitType::INT,
234 PrimitiveCoreType::CORETYPE_USIZE, locus, {});
235
236 // mark the type for this implicit node
237 TyTy::BaseType *expected_ty = nullptr;
238 ok = context->lookup_builtin ("usize", &expected_ty);
239 rust_assert (ok);
240 context->insert_type (capacity_mapping, expected_ty);
241
242 Analysis::NodeMapping array_mapping (crate_num, UNKNOWN_NODEID,
243 mappings->get_next_hir_id (
244 crate_num),
245 UNKNOWN_LOCAL_DEFID);
246
247 TyTy::ArrayType *array
248 = new TyTy::ArrayType (array_mapping.get_hirid (), locus,
249 *literal_capacity,
250 TyTy::TyVar (u8->get_ref ()));
251 context->insert_type (array_mapping, array);
252
253 infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
254 TyTy::TyVar (array->get_ref ()),
255 Mutability::Imm);
256 }
257 break;
258
259 default:
260 gcc_unreachable ();
261 break;
262 }
263
264 return infered;
265}
266
267TyTy::ADTType::ReprOptions
268TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
269{
270 TyTy::ADTType::ReprOptions repr;
271 repr.pack = 0;
272 repr.align = 0;
273
274 for (const auto &attr : attrs)
275 {
276 bool is_repr = attr.get_path ().as_string ().compare ("repr") == 0;
277 if (is_repr)
278 {
279 const AST::AttrInput &input = attr.get_attr_input ();
280 bool is_token_tree = input.get_attr_input_type ()
281 == AST::AttrInput::AttrInputType::TOKEN_TREE;
282 rust_assert (is_token_tree);
283 const auto &option = static_cast<const AST::DelimTokenTree &> (input);
284 AST::AttrInputMetaItemContainer *meta_items
285 = option.parse_to_meta_item ();
286
287 const std::string inline_option
288 = meta_items->get_items ().at (0)->as_string ();
289
290 // TODO: it would probably be better to make the MetaItems more aware
291 // of constructs with nesting like #[repr(packed(2))] rather than
292 // manually parsing the string "packed(2)" here.
293
294 size_t oparen = inline_option.find ('(', 0);
295 bool is_pack = false, is_align = false;
296 unsigned char value = 1;
297
298 if (oparen == std::string::npos)
299 {
300 is_pack = inline_option.compare ("packed") == 0;
301 is_align = inline_option.compare ("align") == 0;
302 }
303
304 else
305 {
306 std::string rep = inline_option.substr (0, oparen);
307 is_pack = rep.compare ("packed") == 0;
308 is_align = rep.compare ("align") == 0;
309
310 size_t cparen = inline_option.find (')', oparen);
311 if (cparen == std::string::npos)
312 {
313 rust_error_at (locus, "malformed attribute");
314 }
315
316 std::string value_str = inline_option.substr (oparen, cparen);
317 value = strtoul (value_str.c_str () + 1, NULL, 10);
318 }
319
320 if (is_pack)
321 repr.pack = value;
322 else if (is_align)
323 repr.align = value;
324
325 // Multiple repr options must be specified with e.g. #[repr(C,
326 // packed(2))].
327 break;
328 }
329 }
330
331 return repr;
332}
333
334TyTy::BaseType *
335TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
336 TyTy::BaseType *expr, Location locus)
337{
338 rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
339 expected->debug_str ().c_str (), expr->debug_str ().c_str ());
340
341 auto context = TypeCheckContext::get ();
342 if (expected->get_kind () == TyTy::TypeKind::ERROR
343 || expr->get_kind () == TyTy::TypeKind::ERROR)
344 return expr;
345
346 // can we autoderef it?
347 auto result = TypeCoercionRules::Coerce (expr, expected, locus);
348
349 // the result needs to be unified
350 TyTy::BaseType *receiver = expr;
351 if (!result.is_error ())
352 {
353 receiver = result.tyty;
354 }
355
356 rust_debug ("coerce_default_unify(a={%s}, b={%s})",
357 receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
358 TyTy::BaseType *coerced = expected->unify (receiver);
359 context->insert_autoderef_mappings (id, std::move (result.adjustments));
360 return coerced;
361}
362
363TyTy::BaseType *
364TypeCheckBase::cast_site (HirId id, TyTy::TyWithLocation from,
365 TyTy::TyWithLocation to, Location cast_locus)
366{
367 rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
368 from.get_ty ()->debug_str ().c_str (),
369 to.get_ty ()->debug_str ().c_str ());
370
371 auto context = TypeCheckContext::get ();
372 if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
373 || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
374 return to.get_ty ();
375
376 // do the cast
377 auto result = TypeCastRules::resolve (cast_locus, from, to);
378
379 // we assume error has already been emitted
380 if (result.is_error ())
381 return to.get_ty ();
382
383 // the result needs to be unified
384 TyTy::BaseType *casted_result = result.tyty;
385 rust_debug ("cast_default_unify(a={%s}, b={%s})",
386 casted_result->debug_str ().c_str (),
387 to.get_ty ()->debug_str ().c_str ());
388 TyTy::BaseType *casted = to.get_ty ()->unify (casted_result);
389 context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
390 return casted;
391}
392
393void
394TypeCheckBase::resolve_generic_params (
395 const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
396 std::vector<TyTy::SubstitutionParamMapping> &substitutions)
397{
398 for (auto &generic_param : generic_params)
399 {
400 switch (generic_param.get ()->get_kind ())
401 {
402 case HIR::GenericParam::GenericKind::LIFETIME:
403 // FIXME: Skipping Lifetime completely until better
404 // handling.
405 break;
406 case HIR::GenericParam::GenericKind::CONST: {
407 auto param
408 = static_cast<HIR::ConstGenericParam *> (generic_param.get ());
409 auto specified_type
410 = TypeCheckType::Resolve (param->get_type ().get ());
411
412 if (param->has_default_expression ())
413 {
414 auto expr_type = TypeCheckExpr::Resolve (
415 param->get_default_expression ().get ());
416
417 specified_type->unify (expr_type);
418 }
419
420 context->insert_type (generic_param->get_mappings (),
421 specified_type);
422 }
423 break;
424
425 case HIR::GenericParam::GenericKind::TYPE: {
426 auto param_type
427 = TypeResolveGenericParam::Resolve (generic_param.get ());
428 context->insert_type (generic_param->get_mappings (), param_type);
429
430 substitutions.push_back (TyTy::SubstitutionParamMapping (
431 static_cast<HIR::TypeParam &> (*generic_param), param_type));
432 }
433 break;
434 }
435 }
436}
437
438} // namespace Resolver
439} // namespace Rust