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.h"
20 : : #include "rust-hir-type-check-expr.h"
21 : : #include "rust-hir-type-check-struct-field.h"
22 : : #include "rust-type-util.h"
23 : :
24 : : namespace Rust {
25 : : namespace Resolver {
26 : :
27 : 1322 : TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e)
28 : : : TypeCheckBase (),
29 : 1322 : resolved (new TyTy::ErrorType (e.get_mappings ().get_hirid ())),
30 : 1322 : struct_path_resolved (nullptr),
31 : 2644 : variant (&TyTy::VariantDef::get_error_node ()), parent (e)
32 : 1322 : {}
33 : :
34 : : TyTy::BaseType *
35 : 1322 : TypeCheckStructExpr::Resolve (HIR::StructExprStructFields &expr)
36 : : {
37 : 1322 : TypeCheckStructExpr resolver (expr);
38 : 1322 : resolver.resolve (expr);
39 : 2644 : return resolver.resolved;
40 : 1322 : }
41 : :
42 : : void
43 : 1322 : TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
44 : : {
45 : 1322 : TyTy::BaseType *struct_path_ty
46 : 1322 : = TypeCheckExpr::Resolve (struct_expr.get_struct_name ());
47 : 1322 : if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
48 : : {
49 : 1 : rust_error_at (struct_expr.get_struct_name ().get_locus (),
50 : : "expected an ADT type for constructor");
51 : 9 : return;
52 : : }
53 : :
54 : 1321 : struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
55 : 1321 : TyTy::ADTType *struct_def = struct_path_resolved;
56 : 1321 : if (struct_expr.has_struct_base ())
57 : : {
58 : 63 : TyTy::BaseType *base_resolved
59 : 63 : = TypeCheckExpr::Resolve (struct_expr.get_struct_base ().get_base ());
60 : 126 : TyTy::BaseType *base_unify = unify_site (
61 : 63 : struct_expr.get_struct_base ().get_base ().get_mappings ().get_hirid (),
62 : 63 : TyTy::TyWithLocation (struct_path_resolved),
63 : 63 : TyTy::TyWithLocation (base_resolved),
64 : 63 : struct_expr.get_struct_base ().get_base ().get_locus ());
65 : :
66 : 63 : if (base_unify->get_kind () != struct_path_ty->get_kind ())
67 : : {
68 : 0 : rust_error_at (
69 : 0 : struct_expr.get_struct_base ().get_base ().get_locus (),
70 : : "incompatible types for base struct reference");
71 : 0 : return;
72 : : }
73 : :
74 : : struct_def = static_cast<TyTy::ADTType *> (base_unify);
75 : : }
76 : :
77 : : // figure out the variant
78 : 1321 : if (struct_path_resolved->is_enum ())
79 : : {
80 : : // lookup variant id
81 : 89 : HirId variant_id;
82 : 89 : bool ok = context->lookup_variant_definition (
83 : 89 : struct_expr.get_struct_name ().get_mappings ().get_hirid (),
84 : : &variant_id);
85 : 89 : if (!ok)
86 : : {
87 : 1 : rich_location r (line_table, struct_expr.get_locus ());
88 : 1 : r.add_range (struct_expr.get_struct_name ().get_locus ());
89 : 1 : rust_error_at (
90 : 1 : struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
91 : : "expected a struct, variant or union type, found enum %qs",
92 : 1 : struct_path_resolved->get_name ().c_str ());
93 : 1 : return;
94 : 1 : }
95 : :
96 : 88 : ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
97 : 88 : rust_assert (ok);
98 : : }
99 : : else
100 : : {
101 : 1232 : rust_assert (struct_path_resolved->number_of_variants () == 1);
102 : 1232 : variant = struct_path_resolved->get_variants ().at (0);
103 : : }
104 : :
105 : 1320 : std::vector<TyTy::StructFieldType *> infered_fields;
106 : : bool ok = true;
107 : :
108 : 3597 : for (auto &field : struct_expr.get_fields ())
109 : : {
110 : 2277 : resolved_field_value_expr = nullptr;
111 : :
112 : 2277 : switch (field->get_kind ())
113 : : {
114 : 216 : case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
115 : 216 : ok = visit (
116 : 216 : static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
117 : 216 : break;
118 : :
119 : 2017 : case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
120 : 2017 : ok = visit (
121 : 2017 : static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
122 : 2017 : break;
123 : :
124 : 44 : case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
125 : 44 : ok = visit (
126 : 44 : static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
127 : 44 : break;
128 : : }
129 : :
130 : 2277 : if (ok)
131 : 2272 : context->insert_type (field->get_mappings (),
132 : : resolved_field_value_expr);
133 : : }
134 : :
135 : : // something failed setting up the fields and error's emitted
136 : 1320 : if (!ok)
137 : : return;
138 : :
139 : : // check the arguments are all assigned and fix up the ordering
140 : 2630 : std::vector<std::string> missing_field_names;
141 : 4547 : for (auto &field : variant->get_fields ())
142 : : {
143 : 3231 : auto it = fields_assigned.find (field->get_name ());
144 : 3231 : if (it == fields_assigned.end ())
145 : : {
146 : 962 : missing_field_names.push_back (field->get_name ());
147 : : }
148 : : }
149 : 1316 : if (!missing_field_names.empty ())
150 : : {
151 : 209 : if (struct_def->is_union ())
152 : : {
153 : 151 : if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
154 : : {
155 : 0 : rust_error_at (
156 : : struct_expr.get_locus (),
157 : : "union must have exactly one field variant assigned");
158 : 2 : return;
159 : : }
160 : : }
161 : 58 : else if (!struct_expr.has_struct_base ())
162 : : {
163 : 2 : Error missing_fields_error
164 : : = make_missing_field_error (struct_expr.get_locus (),
165 : : missing_field_names,
166 : 2 : struct_path_ty->get_name ());
167 : : // We might want to return or handle these in the future emit for now.
168 : 2 : missing_fields_error.emit ();
169 : 2 : return;
170 : 2 : }
171 : : else
172 : : {
173 : : // we have a struct base to assign the missing fields from.
174 : : // the missing fields can be implicit FieldAccessExprs for the value
175 : 56 : std::set<std::string> missing_fields;
176 : 714 : for (auto &field : variant->get_fields ())
177 : : {
178 : 658 : auto it = fields_assigned.find (field->get_name ());
179 : 658 : if (it == fields_assigned.end ())
180 : 616 : missing_fields.insert (field->get_name ());
181 : : }
182 : :
183 : : // we can generate FieldAccessExpr or TupleAccessExpr for the
184 : : // values of the missing fields.
185 : 672 : for (auto &missing : missing_fields)
186 : : {
187 : 616 : HIR::Expr *receiver
188 : 616 : = struct_expr.get_struct_base ().get_base ().clone_expr_impl ();
189 : :
190 : 616 : HIR::StructExprField *implicit_field = nullptr;
191 : :
192 : 616 : AST::AttrVec outer_attribs;
193 : 616 : auto crate_num = mappings.get_current_crate ();
194 : 616 : Analysis::NodeMapping mapping (crate_num,
195 : 616 : struct_expr.get_struct_base ()
196 : 616 : .get_base ()
197 : 616 : .get_mappings ()
198 : : .get_nodeid (),
199 : 616 : mappings.get_next_hir_id (
200 : : crate_num),
201 : 616 : UNKNOWN_LOCAL_DEFID);
202 : :
203 : 616 : HIR::Expr *field_value = new HIR::FieldAccessExpr (
204 : 1848 : mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
205 : : std::move (outer_attribs),
206 : 1848 : struct_expr.get_struct_base ().get_base ().get_locus ());
207 : :
208 : 616 : implicit_field = new HIR::StructExprFieldIdentifierValue (
209 : 1848 : mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
210 : 1232 : struct_expr.get_struct_base ().get_base ().get_locus ());
211 : :
212 : 616 : size_t field_index;
213 : 616 : bool ok = variant->lookup_field (missing, nullptr, &field_index);
214 : 616 : rust_assert (ok);
215 : :
216 : 616 : adtFieldIndexToField[field_index] = implicit_field;
217 : 616 : struct_expr.get_fields ().push_back (
218 : 616 : std::unique_ptr<HIR::StructExprField> (implicit_field));
219 : 616 : }
220 : 56 : }
221 : : }
222 : :
223 : 1314 : if (struct_def->is_union ())
224 : : {
225 : : // There is exactly one field in this constructor, we need to
226 : : // figure out the field index to make sure we initialize the
227 : : // right union field.
228 : 277 : for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
229 : : {
230 : 277 : if (adtFieldIndexToField[i])
231 : : {
232 : 158 : struct_expr.union_index = i;
233 : 158 : break;
234 : : }
235 : : }
236 : 158 : rust_assert (struct_expr.union_index != -1);
237 : : }
238 : : else
239 : : {
240 : : // everything is ok, now we need to ensure all field values are ordered
241 : : // correctly. The GIMPLE backend uses a simple algorithm that assumes each
242 : : // assigned field in the constructor is in the same order as the field in
243 : : // the type
244 : 3880 : for (auto &field : struct_expr.get_fields ())
245 : 2724 : field.release ();
246 : :
247 : 1156 : std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
248 : 3880 : for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
249 : : {
250 : 5448 : ordered_fields.push_back (
251 : 2724 : std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
252 : : }
253 : 1156 : struct_expr.set_fields_as_owner (std::move (ordered_fields));
254 : 1156 : }
255 : :
256 : 1314 : resolved = struct_def;
257 : 1320 : }
258 : :
259 : : bool
260 : 2017 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
261 : : {
262 : 2017 : size_t field_index;
263 : 2017 : TyTy::StructFieldType *field_type;
264 : 2017 : bool ok = variant->lookup_field (field.field_name.as_string (), &field_type,
265 : : &field_index);
266 : 2017 : if (!ok)
267 : : {
268 : 1 : rich_location r (line_table, parent.get_locus ());
269 : 1 : r.add_range (field.get_locus ());
270 : 1 : rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
271 : 1 : field.field_name.as_string ().c_str ());
272 : 1 : return false;
273 : 1 : }
274 : :
275 : 2016 : auto it = adtFieldIndexToField.find (field_index);
276 : 2016 : if (it != adtFieldIndexToField.end ())
277 : : {
278 : 1 : rich_location repeat_location (line_table, field.get_locus ());
279 : 1 : auto prev_field_locus = it->second->get_locus ();
280 : 1 : repeat_location.add_range (prev_field_locus);
281 : :
282 : 1 : rust_error_at (repeat_location, ErrorCode::E0062,
283 : : "field %qs specified more than once",
284 : 1 : field.field_name.as_string ().c_str ());
285 : 1 : return false;
286 : 1 : }
287 : :
288 : 2015 : TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
289 : 2015 : location_t value_locus = field.get_value ().get_locus ();
290 : :
291 : 2015 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
292 : 2015 : resolved_field_value_expr
293 : 4030 : = coercion_site (coercion_site_id,
294 : : TyTy::TyWithLocation (field_type->get_field_type (),
295 : 2015 : field_type->get_locus ()),
296 : 2015 : TyTy::TyWithLocation (value, value_locus),
297 : : field.get_locus ());
298 : 2015 : if (resolved_field_value_expr != nullptr)
299 : : {
300 : 2015 : fields_assigned.insert (field.field_name.as_string ());
301 : 2015 : adtFieldIndexToField[field_index] = &field;
302 : : }
303 : :
304 : : return true;
305 : : }
306 : :
307 : : bool
308 : 44 : TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
309 : : {
310 : 44 : std::string field_name (std::to_string (field.get_tuple_index ()));
311 : :
312 : 44 : size_t field_index;
313 : 44 : TyTy::StructFieldType *field_type;
314 : 44 : bool ok = variant->lookup_field (field_name, &field_type, &field_index);
315 : 44 : if (!ok)
316 : : {
317 : 2 : rich_location r (line_table, parent.get_locus ());
318 : 2 : r.add_range (field.get_locus ());
319 : 2 : rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
320 : : field_name.c_str ());
321 : 2 : return false;
322 : 2 : }
323 : :
324 : 42 : auto it = adtFieldIndexToField.find (field_index);
325 : 42 : if (it != adtFieldIndexToField.end ())
326 : : {
327 : 0 : rich_location repeat_location (line_table, field.get_locus ());
328 : 0 : auto prev_field_locus = it->second->get_locus ();
329 : 0 : repeat_location.add_range (prev_field_locus);
330 : :
331 : 0 : rust_error_at (repeat_location, ErrorCode::E0062,
332 : : "field %qs specified more than once", field_name.c_str ());
333 : 0 : return false;
334 : 0 : }
335 : :
336 : 42 : TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
337 : 42 : location_t value_locus = field.get_value ().get_locus ();
338 : :
339 : 42 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
340 : 42 : resolved_field_value_expr
341 : 84 : = coercion_site (coercion_site_id,
342 : : TyTy::TyWithLocation (field_type->get_field_type (),
343 : 42 : field_type->get_locus ()),
344 : 42 : TyTy::TyWithLocation (value, value_locus),
345 : : field.get_locus ());
346 : 42 : if (resolved_field_value_expr != nullptr)
347 : : {
348 : 42 : fields_assigned.insert (field_name);
349 : 42 : adtFieldIndexToField[field_index] = &field;
350 : : }
351 : :
352 : : return true;
353 : 44 : }
354 : :
355 : : bool
356 : 216 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
357 : : {
358 : 216 : size_t field_index;
359 : 216 : TyTy::StructFieldType *field_type;
360 : 216 : bool ok = variant->lookup_field (field.get_field_name ().as_string (),
361 : : &field_type, &field_index);
362 : 216 : if (!ok)
363 : : {
364 : 1 : rust_error_at (field.get_locus (), "unknown field");
365 : 1 : return false;
366 : : }
367 : :
368 : 215 : auto it = adtFieldIndexToField.find (field_index);
369 : 215 : if (it != adtFieldIndexToField.end ())
370 : : {
371 : 0 : rich_location repeat_location (line_table, field.get_locus ());
372 : 0 : auto prev_field_locus = it->second->get_locus ();
373 : 0 : repeat_location.add_range (prev_field_locus);
374 : :
375 : 0 : rust_error_at (repeat_location, ErrorCode::E0062,
376 : : "field %qs specified more than once",
377 : 0 : field.get_field_name ().as_string ().c_str ());
378 : 0 : return false;
379 : 0 : }
380 : :
381 : : // we can make the field look like a path expr to take advantage of existing
382 : : // code
383 : 215 : Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
384 : 215 : Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
385 : :
386 : 430 : HIR::PathIdentSegment ident_seg (field.get_field_name ().as_string ());
387 : 215 : HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
388 : 430 : HIR::GenericArgs::create_empty ());
389 : 215 : HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
390 : 430 : {});
391 : 215 : TyTy::BaseType *value = TypeCheckExpr::Resolve (expr);
392 : 215 : location_t value_locus = expr.get_locus ();
393 : :
394 : 215 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
395 : 215 : resolved_field_value_expr
396 : 430 : = coercion_site (coercion_site_id,
397 : : TyTy::TyWithLocation (field_type->get_field_type (),
398 : 215 : field_type->get_locus ()),
399 : 215 : TyTy::TyWithLocation (value, value_locus),
400 : : field.get_locus ());
401 : 215 : if (resolved_field_value_expr != nullptr)
402 : :
403 : : {
404 : 215 : fields_assigned.insert (field.get_field_name ().as_string ());
405 : 215 : adtFieldIndexToField[field_index] = &field;
406 : : }
407 : :
408 : 215 : return true;
409 : 430 : }
410 : :
411 : : Error
412 : 3 : TypeCheckStructExpr::make_missing_field_error (
413 : : location_t locus, const std::vector<std::string> &missing_field_names,
414 : : const std::string &struct_name)
415 : : {
416 : : // Message plurality depends on size
417 : 3 : if (missing_field_names.size () == 1)
418 : : {
419 : 1 : return Error (locus, ErrorCode::E0063,
420 : : "missing field %s in initializer of %qs",
421 : 1 : missing_field_names[0].c_str (), struct_name.c_str ());
422 : : }
423 : : // Make comma separated string for display
424 : 2 : std::stringstream display_field_names;
425 : 2 : bool first = true;
426 : 7 : for (auto &name : missing_field_names)
427 : : {
428 : 5 : if (!first)
429 : : {
430 : 3 : display_field_names << ", ";
431 : : }
432 : 5 : first = false;
433 : 10 : display_field_names << name;
434 : : }
435 : 2 : return Error (locus, ErrorCode::E0063,
436 : : "missing fields %s in initializer of %qs",
437 : 2 : display_field_names.str ().c_str (), struct_name.c_str ());
438 : 2 : }
439 : :
440 : : } // namespace Resolver
441 : : } // namespace Rust
|