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
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
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"
27 TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr
*e
)
29 resolved (new TyTy::ErrorType (e
->get_mappings ().get_hirid ())),
30 struct_path_resolved (nullptr),
31 variant (&TyTy::VariantDef::get_error_node ())
35 TypeCheckStructExpr::Resolve (HIR::StructExprStructFields
*expr
)
37 TypeCheckStructExpr
resolver (expr
);
38 resolver
.resolve (*expr
);
39 return resolver
.resolved
;
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");
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");
73 struct_def
= static_cast<TyTy::ADTType
*> (base_unify
);
76 // figure out the variant
77 if (struct_path_resolved
->is_enum ())
81 bool ok
= context
->lookup_variant_definition (
82 struct_expr
.get_struct_name ().get_mappings ().get_hirid (),
86 ok
= struct_path_resolved
->lookup_variant_by_id (variant_id
, &variant
);
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
;
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
:
106 static_cast<HIR::StructExprFieldIdentifier
&> (*field
.get ()));
109 case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE
:
111 static_cast<HIR::StructExprFieldIdentifierValue
&> (*field
.get ()));
114 case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE
:
116 static_cast<HIR::StructExprFieldIndexValue
&> (*field
.get ()));
125 if (resolved_field_value_expr
== nullptr)
127 rust_fatal_error (field
->get_locus (),
128 "failed to resolve type for field");
133 context
->insert_type (field
->get_mappings (), resolved_field_value_expr
);
136 // something failed setting up the fields
139 rust_error_at (struct_expr
.get_locus (),
140 "constructor type resolution failure");
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 ())
161 struct_expr
.get_locus (),
162 "union must have exactly one field variant assigned");
166 else if (!struct_expr
.has_struct_base ())
168 Error missing_fields_error
169 = make_missing_field_error (struct_expr
.get_locus (),
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 ();
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
)
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 (
201 struct_expr
.struct_base
->base_struct
->get_mappings ()
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 ());
215 bool ok
= variant
->lookup_field (missing
, nullptr, &field_index
);
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
;
238 rust_assert (struct_expr
.union_index
!= -1);
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
246 for (auto &field
: struct_expr
.get_fields ())
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
;
262 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue
&field
)
265 TyTy::StructFieldType
*field_type
;
266 bool ok
= variant
->lookup_field (field
.field_name
.as_string (), &field_type
,
270 rust_error_at (field
.get_locus (), "unknown field");
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 ());
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
),
297 if (resolved_field_value_expr
!= nullptr)
299 fields_assigned
.insert (field
.field_name
.as_string ());
300 adtFieldIndexToField
[field_index
] = &field
;
307 TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue
&field
)
309 std::string
field_name (std::to_string (field
.get_tuple_index ()));
312 TyTy::StructFieldType
*field_type
;
313 bool ok
= variant
->lookup_field (field_name
, &field_type
, &field_index
);
316 rust_error_at (field
.get_locus (), "unknown field");
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 ());
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
),
343 if (resolved_field_value_expr
!= nullptr)
345 fields_assigned
.insert (field_name
);
346 adtFieldIndexToField
[field_index
] = &field
;
353 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier
&field
)
356 TyTy::StructFieldType
*field_type
;
357 bool ok
= variant
->lookup_field (field
.get_field_name ().as_string (),
358 &field_type
, &field_index
);
361 rust_error_at (field
.get_locus (), "unknown field");
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 ());
378 // we can make the field look like a path expr to take advantage of existing
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,
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
),
398 if (resolved_field_value_expr
!= nullptr)
401 fields_assigned
.insert (field
.get_field_name ().as_string ());
402 adtFieldIndexToField
[field_index
] = &field
;
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
;
423 for (auto &name
: missing_field_names
)
427 display_field_names
<< ", ";
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