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