libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check-struct.cc
blobd2977ac8ea8461cede2f23d2dd7055df8e9efefe
1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
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"
24 namespace Rust {
25 namespace Resolver {
27 TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e)
28 : TypeCheckBase (),
29 resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())),
30 struct_path_resolved (nullptr),
31 variant (&TyTy::VariantDef::get_error_node ())
34 TyTy::BaseType *
35 TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr)
37 TypeCheckStructExpr resolver (expr);
38 resolver.resolve (*expr);
39 return resolver.resolved;
42 void
43 TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
45 TyTy::BaseType *struct_path_ty
46 = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
47 if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
49 rust_error_at (struct_expr.get_struct_name ().get_locus (),
50 "expected an ADT type for constructor");
51 return;
54 struct_path_resolved = static_cast<TyTy::ADTType *> (struct_path_ty);
55 TyTy::ADTType *struct_def = struct_path_resolved;
56 if (struct_expr.has_struct_base ())
58 TyTy::BaseType *base_resolved
59 = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
60 TyTy::BaseType *base_unify = unify_site (
61 struct_expr.struct_base->base_struct->get_mappings ().get_hirid (),
62 TyTy::TyWithLocation (struct_path_resolved),
63 TyTy::TyWithLocation (base_resolved),
64 struct_expr.struct_base->base_struct->get_locus ());
66 if (base_unify->get_kind () != struct_path_ty->get_kind ())
68 rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
69 "incompatible types for base struct reference");
70 return;
73 struct_def = static_cast<TyTy::ADTType *> (base_unify);
76 // figure out the variant
77 if (struct_path_resolved->is_enum ())
79 // lookup variant id
80 HirId variant_id;
81 bool ok = context->lookup_variant_definition (
82 struct_expr.get_struct_name ().get_mappings ().get_hirid (),
83 &variant_id);
84 rust_assert (ok);
86 ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
87 rust_assert (ok);
89 else
91 rust_assert (struct_path_resolved->number_of_variants () == 1);
92 variant = struct_path_resolved->get_variants ().at (0);
95 std::vector<TyTy::StructFieldType *> infered_fields;
96 bool ok = true;
98 for (auto &field : struct_expr.get_fields ())
100 resolved_field_value_expr = nullptr;
102 switch (field->get_kind ())
104 case HIR::StructExprField::StructExprFieldKind::IDENTIFIER:
105 ok = visit (
106 static_cast<HIR::StructExprFieldIdentifier &> (*field.get ()));
107 break;
109 case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE:
110 ok = visit (
111 static_cast<HIR::StructExprFieldIdentifierValue &> (*field.get ()));
112 break;
114 case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE:
115 ok = visit (
116 static_cast<HIR::StructExprFieldIndexValue &> (*field.get ()));
117 break;
120 if (!ok)
122 return;
125 if (resolved_field_value_expr == nullptr)
127 rust_fatal_error (field->get_locus (),
128 "failed to resolve type for field");
129 ok = false;
130 break;
133 context->insert_type (field->get_mappings (), resolved_field_value_expr);
136 // something failed setting up the fields
137 if (!ok)
139 rust_error_at (struct_expr.get_locus (),
140 "constructor type resolution failure");
141 return;
144 // check the arguments are all assigned and fix up the ordering
145 std::vector<std::string> missing_field_names;
146 for (auto &field : variant->get_fields ())
148 auto it = fields_assigned.find (field->get_name ());
149 if (it == fields_assigned.end ())
151 missing_field_names.push_back (field->get_name ());
154 if (!missing_field_names.empty ())
156 if (struct_def->is_union ())
158 if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
160 rust_error_at (
161 struct_expr.get_locus (),
162 "union must have exactly one field variant assigned");
163 return;
166 else if (!struct_expr.has_struct_base ())
168 Error missing_fields_error
169 = make_missing_field_error (struct_expr.get_locus (),
170 missing_field_names,
171 struct_path_ty->get_name ());
172 // We might want to return or handle these in the future emit for now.
173 missing_fields_error.emit ();
174 return;
176 else
178 // we have a struct base to assign the missing fields from.
179 // the missing fields can be implicit FieldAccessExprs for the value
180 std::set<std::string> missing_fields;
181 for (auto &field : variant->get_fields ())
183 auto it = fields_assigned.find (field->get_name ());
184 if (it == fields_assigned.end ())
185 missing_fields.insert (field->get_name ());
188 // we can generate FieldAccessExpr or TupleAccessExpr for the
189 // values of the missing fields.
190 for (auto &missing : missing_fields)
192 HIR::Expr *receiver
193 = struct_expr.struct_base->base_struct->clone_expr_impl ();
195 HIR::StructExprField *implicit_field = nullptr;
197 AST::AttrVec outer_attribs;
198 auto crate_num = mappings->get_current_crate ();
199 Analysis::NodeMapping mapping (
200 crate_num,
201 struct_expr.struct_base->base_struct->get_mappings ()
202 .get_nodeid (),
203 mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
205 HIR::Expr *field_value = new HIR::FieldAccessExpr (
206 mapping, std::unique_ptr<HIR::Expr> (receiver), missing,
207 std::move (outer_attribs),
208 struct_expr.struct_base->base_struct->get_locus ());
210 implicit_field = new HIR::StructExprFieldIdentifierValue (
211 mapping, missing, std::unique_ptr<HIR::Expr> (field_value),
212 struct_expr.struct_base->base_struct->get_locus ());
214 size_t field_index;
215 bool ok = variant->lookup_field (missing, nullptr, &field_index);
216 rust_assert (ok);
218 adtFieldIndexToField[field_index] = implicit_field;
219 struct_expr.get_fields ().push_back (
220 std::unique_ptr<HIR::StructExprField> (implicit_field));
225 if (struct_def->is_union ())
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 for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
232 if (adtFieldIndexToField[i])
234 struct_expr.union_index = i;
235 break;
238 rust_assert (struct_expr.union_index != -1);
240 else
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 for (auto &field : struct_expr.get_fields ())
247 field.release ();
249 std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
250 for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
252 ordered_fields.push_back (
253 std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
255 struct_expr.set_fields_as_owner (std::move (ordered_fields));
258 resolved = struct_def;
261 bool
262 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
264 size_t field_index;
265 TyTy::StructFieldType *field_type;
266 bool ok = variant->lookup_field (field.field_name.as_string (), &field_type,
267 &field_index);
268 if (!ok)
270 rust_error_at (field.get_locus (), "unknown field");
271 return true;
274 auto it = adtFieldIndexToField.find (field_index);
275 if (it != adtFieldIndexToField.end ())
277 rich_location repeat_location (line_table, field.get_locus ());
278 auto prev_field_locus = it->second->get_locus ();
279 repeat_location.add_range (prev_field_locus);
281 rust_error_at (repeat_location, ErrorCode::E0062,
282 "field %<%s%> specified more than once",
283 field.field_name.as_string ().c_str ());
284 return false;
287 TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ());
288 location_t value_locus = field.get_value ()->get_locus ();
290 HirId coercion_site_id = field.get_mappings ().get_hirid ();
291 resolved_field_value_expr
292 = coercion_site (coercion_site_id,
293 TyTy::TyWithLocation (field_type->get_field_type (),
294 field_type->get_locus ()),
295 TyTy::TyWithLocation (value, value_locus),
296 field.get_locus ());
297 if (resolved_field_value_expr != nullptr)
299 fields_assigned.insert (field.field_name.as_string ());
300 adtFieldIndexToField[field_index] = &field;
303 return true;
306 bool
307 TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
309 std::string field_name (std::to_string (field.get_tuple_index ()));
311 size_t field_index;
312 TyTy::StructFieldType *field_type;
313 bool ok = variant->lookup_field (field_name, &field_type, &field_index);
314 if (!ok)
316 rust_error_at (field.get_locus (), "unknown field");
317 return true;
320 auto it = adtFieldIndexToField.find (field_index);
321 if (it != adtFieldIndexToField.end ())
323 rich_location repeat_location (line_table, field.get_locus ());
324 auto prev_field_locus = it->second->get_locus ();
325 repeat_location.add_range (prev_field_locus);
327 rust_error_at (repeat_location, ErrorCode::E0062,
328 "field %<%s%> specified more than once",
329 field_name.c_str ());
330 return false;
333 TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ());
334 location_t value_locus = field.get_value ()->get_locus ();
336 HirId coercion_site_id = field.get_mappings ().get_hirid ();
337 resolved_field_value_expr
338 = coercion_site (coercion_site_id,
339 TyTy::TyWithLocation (field_type->get_field_type (),
340 field_type->get_locus ()),
341 TyTy::TyWithLocation (value, value_locus),
342 field.get_locus ());
343 if (resolved_field_value_expr != nullptr)
345 fields_assigned.insert (field_name);
346 adtFieldIndexToField[field_index] = &field;
349 return true;
352 bool
353 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
355 size_t field_index;
356 TyTy::StructFieldType *field_type;
357 bool ok = variant->lookup_field (field.get_field_name ().as_string (),
358 &field_type, &field_index);
359 if (!ok)
361 rust_error_at (field.get_locus (), "unknown field");
362 return true;
365 auto it = adtFieldIndexToField.find (field_index);
366 if (it != adtFieldIndexToField.end ())
368 rich_location repeat_location (line_table, field.get_locus ());
369 auto prev_field_locus = it->second->get_locus ();
370 repeat_location.add_range (prev_field_locus);
372 rust_error_at (repeat_location, ErrorCode::E0062,
373 "field %<%s%> specified more than once",
374 field.get_field_name ().as_string ().c_str ());
375 return false;
378 // we can make the field look like a path expr to take advantage of existing
379 // code
380 Analysis::NodeMapping mappings_copy1 = field.get_mappings ();
381 Analysis::NodeMapping mappings_copy2 = field.get_mappings ();
383 HIR::PathIdentSegment ident_seg (field.get_field_name ().as_string ());
384 HIR::PathExprSegment seg (mappings_copy1, ident_seg, field.get_locus (),
385 HIR::GenericArgs::create_empty ());
386 HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false,
387 {});
388 TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
389 location_t value_locus = expr.get_locus ();
391 HirId coercion_site_id = field.get_mappings ().get_hirid ();
392 resolved_field_value_expr
393 = coercion_site (coercion_site_id,
394 TyTy::TyWithLocation (field_type->get_field_type (),
395 field_type->get_locus ()),
396 TyTy::TyWithLocation (value, value_locus),
397 field.get_locus ());
398 if (resolved_field_value_expr != nullptr)
401 fields_assigned.insert (field.get_field_name ().as_string ());
402 adtFieldIndexToField[field_index] = &field;
405 return true;
408 Error
409 TypeCheckStructExpr::make_missing_field_error (
410 location_t locus, const std::vector<std::string> &missing_field_names,
411 const std::string &struct_name)
413 // Message plurality depends on size
414 if (missing_field_names.size () == 1)
416 return Error (locus, ErrorCode::E0063,
417 "missing field %s in initializer of %qs",
418 missing_field_names[0].c_str (), struct_name.c_str ());
420 // Make comma separated string for display
421 std::stringstream display_field_names;
422 bool first = true;
423 for (auto &name : missing_field_names)
425 if (!first)
427 display_field_names << ", ";
429 first = false;
430 display_field_names << name;
432 return Error (locus, ErrorCode::E0063,
433 "missing fields %s in initializer of %qs",
434 display_field_names.str ().c_str (), struct_name.c_str ());
437 } // namespace Resolver
438 } // namespace Rust