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-full.h"
21 #include "rust-hir-type-check-expr.h"
22 #include "rust-hir-type-check-struct-field.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
:
105 visit (static_cast<HIR::StructExprFieldIdentifier
&> (*field
.get ()));
108 case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE
:
110 static_cast<HIR::StructExprFieldIdentifierValue
&> (*field
.get ()));
113 case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE
:
114 visit (static_cast<HIR::StructExprFieldIndexValue
&> (*field
.get ()));
118 if (resolved_field_value_expr
== nullptr)
120 rust_fatal_error (field
->get_locus (),
121 "failed to resolve type for field");
126 context
->insert_type (field
->get_mappings (), resolved_field_value_expr
);
129 // something failed setting up the fields
132 rust_error_at (struct_expr
.get_locus (),
133 "constructor type resolution failure");
137 // check the arguments are all assigned and fix up the ordering
138 if (fields_assigned
.size () != variant
->num_fields ())
140 if (struct_def
->is_union ())
142 if (fields_assigned
.size () != 1 || struct_expr
.has_struct_base ())
145 struct_expr
.get_locus (),
146 "union must have exactly one field variant assigned");
150 else if (!struct_expr
.has_struct_base ())
152 rust_error_at (struct_expr
.get_locus (),
153 "constructor is missing fields");
158 // we have a struct base to assign the missing fields from.
159 // the missing fields can be implicit FieldAccessExprs for the value
160 std::set
<std::string
> missing_fields
;
161 for (auto &field
: variant
->get_fields ())
163 auto it
= fields_assigned
.find (field
->get_name ());
164 if (it
== fields_assigned
.end ())
165 missing_fields
.insert (field
->get_name ());
168 // we can generate FieldAccessExpr or TupleAccessExpr for the
169 // values of the missing fields.
170 for (auto &missing
: missing_fields
)
173 = struct_expr
.struct_base
->base_struct
->clone_expr_impl ();
175 HIR::StructExprField
*implicit_field
= nullptr;
177 AST::AttrVec outer_attribs
;
178 auto crate_num
= mappings
->get_current_crate ();
179 Analysis::NodeMapping
mapping (
181 struct_expr
.struct_base
->base_struct
->get_mappings ()
183 mappings
->get_next_hir_id (crate_num
), UNKNOWN_LOCAL_DEFID
);
185 HIR::Expr
*field_value
= new HIR::FieldAccessExpr (
186 mapping
, std::unique_ptr
<HIR::Expr
> (receiver
), missing
,
187 std::move (outer_attribs
),
188 struct_expr
.struct_base
->base_struct
->get_locus ());
190 implicit_field
= new HIR::StructExprFieldIdentifierValue (
191 mapping
, missing
, std::unique_ptr
<HIR::Expr
> (field_value
),
192 struct_expr
.struct_base
->base_struct
->get_locus ());
195 bool ok
= variant
->lookup_field (missing
, nullptr, &field_index
);
198 adtFieldIndexToField
[field_index
] = implicit_field
;
199 struct_expr
.get_fields ().push_back (
200 std::unique_ptr
<HIR::StructExprField
> (implicit_field
));
205 if (struct_def
->is_union ())
207 // There is exactly one field in this constructor, we need to
208 // figure out the field index to make sure we initialize the
209 // right union field.
210 for (size_t i
= 0; i
< adtFieldIndexToField
.size (); i
++)
212 if (adtFieldIndexToField
[i
])
214 struct_expr
.union_index
= i
;
218 rust_assert (struct_expr
.union_index
!= -1);
222 // everything is ok, now we need to ensure all field values are ordered
223 // correctly. The GIMPLE backend uses a simple algorithm that assumes each
224 // assigned field in the constructor is in the same order as the field in
226 for (auto &field
: struct_expr
.get_fields ())
229 std::vector
<std::unique_ptr
<HIR::StructExprField
> > ordered_fields
;
230 for (size_t i
= 0; i
< adtFieldIndexToField
.size (); i
++)
232 ordered_fields
.push_back (
233 std::unique_ptr
<HIR::StructExprField
> (adtFieldIndexToField
[i
]));
235 struct_expr
.set_fields_as_owner (std::move (ordered_fields
));
238 resolved
= struct_def
;
242 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue
&field
)
244 auto it
= fields_assigned
.find (field
.field_name
);
245 if (it
!= fields_assigned
.end ())
247 rust_fatal_error (field
.get_locus (), "used more than once");
252 TyTy::StructFieldType
*field_type
;
253 bool ok
= variant
->lookup_field (field
.field_name
, &field_type
, &field_index
);
256 rust_error_at (field
.get_locus (), "unknown field");
260 TyTy::BaseType
*value
= TypeCheckExpr::Resolve (field
.get_value ());
261 Location value_locus
= field
.get_value ()->get_locus ();
263 HirId coercion_site_id
= field
.get_mappings ().get_hirid ();
264 resolved_field_value_expr
265 = coercion_site (coercion_site_id
,
266 TyTy::TyWithLocation (field_type
->get_field_type (),
267 field_type
->get_locus ()),
268 TyTy::TyWithLocation (value
, value_locus
),
270 if (resolved_field_value_expr
!= nullptr)
272 fields_assigned
.insert (field
.field_name
);
273 adtFieldIndexToField
[field_index
] = &field
;
278 TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue
&field
)
280 std::string
field_name (std::to_string (field
.get_tuple_index ()));
281 auto it
= fields_assigned
.find (field_name
);
282 if (it
!= fields_assigned
.end ())
284 rust_fatal_error (field
.get_locus (), "used more than once");
289 TyTy::StructFieldType
*field_type
;
290 bool ok
= variant
->lookup_field (field_name
, &field_type
, &field_index
);
293 rust_error_at (field
.get_locus (), "unknown field");
297 TyTy::BaseType
*value
= TypeCheckExpr::Resolve (field
.get_value ());
298 Location value_locus
= field
.get_value ()->get_locus ();
300 HirId coercion_site_id
= field
.get_mappings ().get_hirid ();
301 resolved_field_value_expr
302 = coercion_site (coercion_site_id
,
303 TyTy::TyWithLocation (field_type
->get_field_type (),
304 field_type
->get_locus ()),
305 TyTy::TyWithLocation (value
, value_locus
),
307 if (resolved_field_value_expr
!= nullptr)
309 fields_assigned
.insert (field_name
);
310 adtFieldIndexToField
[field_index
] = &field
;
315 TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier
&field
)
317 auto it
= fields_assigned
.find (field
.get_field_name ());
318 if (it
!= fields_assigned
.end ())
320 rust_fatal_error (field
.get_locus (), "used more than once");
325 TyTy::StructFieldType
*field_type
;
326 bool ok
= variant
->lookup_field (field
.get_field_name (), &field_type
,
330 rust_error_at (field
.get_locus (), "unknown field");
334 // we can make the field look like a path expr to take advantage of existing
336 Analysis::NodeMapping mappings_copy1
= field
.get_mappings ();
337 Analysis::NodeMapping mappings_copy2
= field
.get_mappings ();
339 HIR::PathIdentSegment
ident_seg (field
.get_field_name ());
340 HIR::PathExprSegment
seg (mappings_copy1
, ident_seg
, field
.get_locus (),
341 HIR::GenericArgs::create_empty ());
342 HIR::PathInExpression
expr (mappings_copy2
, {seg
}, field
.get_locus (), false,
344 TyTy::BaseType
*value
= TypeCheckExpr::Resolve (&expr
);
345 Location value_locus
= expr
.get_locus ();
347 HirId coercion_site_id
= field
.get_mappings ().get_hirid ();
348 resolved_field_value_expr
349 = coercion_site (coercion_site_id
,
350 TyTy::TyWithLocation (field_type
->get_field_type (),
351 field_type
->get_locus ()),
352 TyTy::TyWithLocation (value
, value_locus
),
354 if (resolved_field_value_expr
!= nullptr)
357 fields_assigned
.insert (field
.get_field_name ());
358 adtFieldIndexToField
[field_index
] = &field
;
362 } // namespace Resolver