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 : 1098 : TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e)
28 : : : TypeCheckBase (),
29 : 1098 : resolved (new TyTy::ErrorType (e.get_mappings ().get_hirid ())),
30 : 1098 : struct_path_resolved (nullptr),
31 : 2196 : variant (&TyTy::VariantDef::get_error_node ()), parent (e)
32 : 1098 : {}
33 : :
34 : : TyTy::BaseType *
35 : 1098 : TypeCheckStructExpr::Resolve (HIR::StructExprStructFields &expr)
36 : : {
37 : 1098 : TypeCheckStructExpr resolver (expr);
38 : 1098 : resolver.resolve (expr);
39 : 2196 : return resolver.resolved;
40 : 1098 : }
41 : :
42 : : void
43 : 1098 : TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
44 : : {
45 : 1098 : TyTy::BaseType *struct_path_ty
46 : 1098 : = TypeCheckExpr::Resolve (struct_expr.get_struct_name ());
47 : 1098 : if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
48 : : {
49 : 0 : rust_error_at (struct_expr.get_struct_name ().get_locus (),
50 : : "expected an ADT type for constructor");
51 : 12 : return;
52 : : }
53 : :
54 : 1098 : struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
55 : 1098 : TyTy::ADTType *struct_def = struct_path_resolved;
56 : 1098 : if (struct_expr.has_struct_base ())
57 : : {
58 : 72 : TyTy::BaseType *base_resolved
59 : 72 : = TypeCheckExpr::Resolve (struct_expr.get_struct_base ().get_base ());
60 : 144 : TyTy::BaseType *base_unify = unify_site (
61 : 72 : struct_expr.get_struct_base ().get_base ().get_mappings ().get_hirid (),
62 : 72 : TyTy::TyWithLocation (struct_path_resolved),
63 : 72 : TyTy::TyWithLocation (base_resolved),
64 : 72 : struct_expr.get_struct_base ().get_base ().get_locus ());
65 : :
66 : 72 : 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 : 1098 : if (struct_path_resolved->is_enum ())
79 : : {
80 : : // lookup variant id
81 : 51 : HirId variant_id;
82 : 51 : bool ok = context->lookup_variant_definition (
83 : 51 : struct_expr.get_struct_name ().get_mappings ().get_hirid (),
84 : : &variant_id);
85 : 51 : if (!ok)
86 : : {
87 : 2 : rich_location r (line_table, struct_expr.get_locus ());
88 : 2 : r.add_range (struct_expr.get_struct_name ().get_locus ());
89 : 2 : rust_error_at (
90 : 2 : struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
91 : : "expected a struct, variant or union type, found enum %qs",
92 : 2 : struct_path_resolved->get_name ().c_str ());
93 : 2 : return;
94 : 2 : }
95 : :
96 : 49 : ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
97 : 49 : rust_assert (ok);
98 : : }
99 : : else
100 : : {
101 : 1047 : rust_assert (struct_path_resolved->number_of_variants () == 1);
102 : 1047 : variant = struct_path_resolved->get_variants ().at (0);
103 : : }
104 : :
105 : 1096 : std::vector<TyTy::StructFieldType *> infered_fields;
106 : : bool ok = true;
107 : :
108 : 3076 : for (auto &field : struct_expr.get_fields ())
109 : : {
110 : 1980 : resolved_field_value_expr = nullptr;
111 : :
112 : 1980 : switch (field->get_kind ())
113 : : {
114 : 234 : case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
115 : 234 : ok = visit (
116 : 234 : static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
117 : 234 : break;
118 : :
119 : 1694 : case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
120 : 1694 : ok = visit (
121 : 1694 : static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
122 : 1694 : break;
123 : :
124 : 52 : case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
125 : 52 : ok = visit (
126 : 52 : static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
127 : 52 : break;
128 : : }
129 : :
130 : 1980 : if (ok)
131 : 1972 : 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 : 1096 : if (!ok)
137 : : return;
138 : :
139 : : // check the arguments are all assigned and fix up the ordering
140 : 2176 : std::vector<std::string> missing_field_names;
141 : 4116 : for (auto &field : variant->get_fields ())
142 : : {
143 : 3026 : auto it = fields_assigned.find (field->get_name ());
144 : 3026 : if (it == fields_assigned.end ())
145 : : {
146 : 1060 : missing_field_names.push_back (field->get_name ());
147 : : }
148 : : }
149 : 1090 : if (!missing_field_names.empty ())
150 : : {
151 : 219 : 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 : 4 : return;
159 : : }
160 : : }
161 : 68 : else if (!struct_expr.has_struct_base ())
162 : : {
163 : 4 : Error missing_fields_error
164 : : = make_missing_field_error (struct_expr.get_locus (),
165 : : missing_field_names,
166 : 4 : struct_path_ty->get_name ());
167 : : // We might want to return or handle these in the future emit for now.
168 : 4 : missing_fields_error.emit ();
169 : 4 : return;
170 : 4 : }
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 : 64 : std::set<std::string> missing_fields;
176 : 816 : for (auto &field : variant->get_fields ())
177 : : {
178 : 752 : auto it = fields_assigned.find (field->get_name ());
179 : 752 : if (it == fields_assigned.end ())
180 : 704 : missing_fields.insert (field->get_name ());
181 : : }
182 : :
183 : : // we can generate FieldAccessExpr or TupleAccessExpr for the
184 : : // values of the missing fields.
185 : 768 : for (auto &missing : missing_fields)
186 : : {
187 : 704 : HIR::Expr *receiver
188 : 704 : = struct_expr.get_struct_base ().get_base ().clone_expr_impl ();
189 : :
190 : 704 : HIR::StructExprField *implicit_field = nullptr;
191 : :
192 : 704 : AST::AttrVec outer_attribs;
193 : 704 : auto crate_num = mappings.get_current_crate ();
194 : 704 : Analysis::NodeMapping mapping (crate_num,
195 : 704 : struct_expr.get_struct_base ()
196 : 704 : .get_base ()
197 : 704 : .get_mappings ()
198 : : .get_nodeid (),
199 : 704 : mappings.get_next_hir_id (
200 : : crate_num),
201 : 704 : UNKNOWN_LOCAL_DEFID);
202 : :
203 : 704 : HIR::Expr *field_value = new HIR::FieldAccessExpr (
204 : 2112 : mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
205 : : std::move (outer_attribs),
206 : 2112 : struct_expr.get_struct_base ().get_base ().get_locus ());
207 : :
208 : 704 : implicit_field = new HIR::StructExprFieldIdentifierValue (
209 : 2112 : mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
210 : 1408 : struct_expr.get_struct_base ().get_base ().get_locus ());
211 : :
212 : 704 : size_t field_index;
213 : 704 : bool ok = variant->lookup_field (missing, nullptr, &field_index);
214 : 704 : rust_assert (ok);
215 : :
216 : 704 : adtFieldIndexToField[field_index] = implicit_field;
217 : 704 : struct_expr.get_fields ().push_back (
218 : 704 : std::unique_ptr<HIR::StructExprField> (implicit_field));
219 : 704 : }
220 : 64 : }
221 : : }
222 : :
223 : 1086 : 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 : 281 : for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
229 : : {
230 : 281 : if (adtFieldIndexToField[i])
231 : : {
232 : 159 : struct_expr.union_index = i;
233 : 159 : break;
234 : : }
235 : : }
236 : 159 : 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 : 3432 : for (auto &field : struct_expr.get_fields ())
245 : 2505 : field.release ();
246 : :
247 : 927 : std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
248 : 3432 : for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
249 : : {
250 : 5010 : ordered_fields.push_back (
251 : 2505 : std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
252 : : }
253 : 927 : struct_expr.set_fields_as_owner (std::move (ordered_fields));
254 : 927 : }
255 : :
256 : 1086 : resolved = struct_def;
257 : 1096 : }
258 : :
259 : : bool
260 : 1694 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
261 : : {
262 : 1694 : size_t field_index;
263 : 1694 : TyTy::StructFieldType *field_type;
264 : 1694 : bool ok = variant->lookup_field (field.field_name.as_string (), &field_type,
265 : : &field_index);
266 : 1694 : if (!ok)
267 : : {
268 : 2 : rich_location r (line_table, parent.get_locus ());
269 : 2 : r.add_range (field.get_locus ());
270 : 2 : rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
271 : 2 : field.field_name.as_string ().c_str ());
272 : 2 : return false;
273 : 2 : }
274 : :
275 : 1692 : auto it = adtFieldIndexToField.find (field_index);
276 : 1692 : if (it != adtFieldIndexToField.end ())
277 : : {
278 : 2 : rich_location repeat_location (line_table, field.get_locus ());
279 : 2 : auto prev_field_locus = it->second->get_locus ();
280 : 2 : repeat_location.add_range (prev_field_locus);
281 : :
282 : 2 : rust_error_at (repeat_location, ErrorCode::E0062,
283 : : "field %qs specified more than once",
284 : 2 : field.field_name.as_string ().c_str ());
285 : 2 : return false;
286 : 2 : }
287 : :
288 : 1690 : TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
289 : 1690 : location_t value_locus = field.get_value ().get_locus ();
290 : :
291 : 1690 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
292 : 1690 : resolved_field_value_expr
293 : 3380 : = coercion_site (coercion_site_id,
294 : : TyTy::TyWithLocation (field_type->get_field_type (),
295 : 1690 : field_type->get_locus ()),
296 : 1690 : TyTy::TyWithLocation (value, value_locus),
297 : : field.get_locus ());
298 : 1690 : if (resolved_field_value_expr != nullptr)
299 : : {
300 : 1690 : fields_assigned.insert (field.field_name.as_string ());
301 : 1690 : adtFieldIndexToField[field_index] = &field;
302 : : }
303 : :
304 : : return true;
305 : : }
306 : :
307 : : bool
308 : 52 : TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
309 : : {
310 : 52 : std::string field_name (std::to_string (field.get_tuple_index ()));
311 : :
312 : 52 : size_t field_index;
313 : 52 : TyTy::StructFieldType *field_type;
314 : 52 : bool ok = variant->lookup_field (field_name, &field_type, &field_index);
315 : 52 : if (!ok)
316 : : {
317 : 4 : rich_location r (line_table, parent.get_locus ());
318 : 4 : r.add_range (field.get_locus ());
319 : 4 : rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
320 : : field_name.c_str ());
321 : 4 : return false;
322 : 4 : }
323 : :
324 : 48 : auto it = adtFieldIndexToField.find (field_index);
325 : 48 : 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",
333 : : field_name.c_str ());
334 : 0 : return false;
335 : 0 : }
336 : :
337 : 48 : TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
338 : 48 : location_t value_locus = field.get_value ().get_locus ();
339 : :
340 : 48 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
341 : 48 : resolved_field_value_expr
342 : 96 : = coercion_site (coercion_site_id,
343 : : TyTy::TyWithLocation (field_type->get_field_type (),
344 : 48 : field_type->get_locus ()),
345 : 48 : TyTy::TyWithLocation (value, value_locus),
346 : : field.get_locus ());
347 : 48 : if (resolved_field_value_expr != nullptr)
348 : : {
349 : 48 : fields_assigned.insert (field_name);
350 : 48 : adtFieldIndexToField[field_index] = &field;
351 : : }
352 : :
353 : : return true;
354 : 52 : }
355 : :
356 : : bool
357 : 234 : TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
358 : : {
359 : 234 : size_t field_index;
360 : 234 : TyTy::StructFieldType *field_type;
361 : 234 : bool ok = variant->lookup_field (field.get_field_name ().as_string (),
362 : : &field_type, &field_index);
363 : 234 : if (!ok)
364 : : {
365 : 0 : rust_error_at (field.get_locus (), "unknown field");
366 : 0 : return true;
367 : : }
368 : :
369 : 234 : auto it = adtFieldIndexToField.find (field_index);
370 : 234 : if (it != adtFieldIndexToField.end ())
371 : : {
372 : 0 : rich_location repeat_location (line_table, field.get_locus ());
373 : 0 : auto prev_field_locus = it->second->get_locus ();
374 : 0 : repeat_location.add_range (prev_field_locus);
375 : :
376 : 0 : rust_error_at (repeat_location, ErrorCode::E0062,
377 : : "field %qs specified more than once",
378 : 0 : field.get_field_name ().as_string ().c_str ());
379 : 0 : return false;
380 : 0 : }
381 : :
382 : : // we can make the field look like a path expr to take advantage of existing
383 : : // code
384 : 234 : Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
385 : 234 : Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
386 : :
387 : 468 : HIR::PathIdentSegment ident_seg (field.get_field_name ().as_string ());
388 : 234 : HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
389 : 468 : HIR::GenericArgs::create_empty ());
390 : 234 : HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
391 : 468 : {});
392 : 234 : TyTy::BaseType *value = TypeCheckExpr::Resolve (expr);
393 : 234 : location_t value_locus = expr.get_locus ();
394 : :
395 : 234 : HirId coercion_site_id = field.get_mappings ().get_hirid ();
396 : 234 : resolved_field_value_expr
397 : 468 : = coercion_site (coercion_site_id,
398 : : TyTy::TyWithLocation (field_type->get_field_type (),
399 : 234 : field_type->get_locus ()),
400 : 234 : TyTy::TyWithLocation (value, value_locus),
401 : : field.get_locus ());
402 : 234 : if (resolved_field_value_expr != nullptr)
403 : :
404 : : {
405 : 234 : fields_assigned.insert (field.get_field_name ().as_string ());
406 : 234 : adtFieldIndexToField[field_index] = &field;
407 : : }
408 : :
409 : 234 : return true;
410 : 468 : }
411 : :
412 : : Error
413 : 6 : TypeCheckStructExpr::make_missing_field_error (
414 : : location_t locus, const std::vector<std::string> &missing_field_names,
415 : : const std::string &struct_name)
416 : : {
417 : : // Message plurality depends on size
418 : 6 : if (missing_field_names.size () == 1)
419 : : {
420 : 2 : return Error (locus, ErrorCode::E0063,
421 : : "missing field %s in initializer of %qs",
422 : 2 : missing_field_names[0].c_str (), struct_name.c_str ());
423 : : }
424 : : // Make comma separated string for display
425 : 4 : std::stringstream display_field_names;
426 : 4 : bool first = true;
427 : 14 : for (auto &name : missing_field_names)
428 : : {
429 : 10 : if (!first)
430 : : {
431 : 6 : display_field_names << ", ";
432 : : }
433 : 10 : first = false;
434 : 20 : display_field_names << name;
435 : : }
436 : 4 : return Error (locus, ErrorCode::E0063,
437 : : "missing fields %s in initializer of %qs",
438 : 4 : display_field_names.str ().c_str (), struct_name.c_str ());
439 : 4 : }
440 : :
441 : : } // namespace Resolver
442 : : } // namespace Rust
|