]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | namespace Rust { | |
26 | namespace Resolver { | |
27 | ||
28 | bool | |
29 | TypeCheckBase::check_for_unconstrained ( | |
30 | const std::vector<TyTy::SubstitutionParamMapping> ¶ms_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 | ||
87 | TyTy::BaseType * | |
88 | TypeCheckBase::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 | ||
267 | TyTy::ADTType::ReprOptions | |
268 | TypeCheckBase::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 | ||
334 | TyTy::BaseType * | |
335 | TypeCheckBase::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 | ||
363 | TyTy::BaseType * | |
364 | TypeCheckBase::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 | ||
393 | void | |
394 | TypeCheckBase::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 |