Line data Source code
1 : // Copyright (C) 2020-2026 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-coercion.h"
20 : #include "rust-type-util.h"
21 : #include "rust-tyty.h"
22 :
23 : namespace Rust {
24 : namespace Resolver {
25 :
26 : TypeCoercionRules::CoercionResult
27 42954 : TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
28 : location_t locus, bool allow_autoderef,
29 : bool is_cast_site)
30 : {
31 42954 : TypeCoercionRules resolver (expected, locus, true, allow_autoderef, false,
32 42954 : is_cast_site);
33 42954 : bool ok = resolver.do_coercion (receiver);
34 85854 : return ok ? resolver.try_result : CoercionResult::get_error ();
35 42954 : }
36 :
37 : TypeCoercionRules::CoercionResult
38 35133 : TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
39 : TyTy::BaseType *expected, location_t locus,
40 : bool allow_autoderef, bool is_cast_site)
41 : {
42 35133 : TypeCoercionRules resolver (expected, locus, false, allow_autoderef, true,
43 35133 : is_cast_site);
44 35133 : bool ok = resolver.do_coercion (receiver);
45 44756 : return ok ? resolver.try_result : CoercionResult::get_error ();
46 35133 : }
47 :
48 78087 : TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected,
49 : location_t locus, bool emit_errors,
50 : bool allow_autoderef, bool try_flag,
51 : bool is_cast_site)
52 156174 : : AutoderefCycle (!allow_autoderef), mappings (Analysis::Mappings::get ()),
53 78087 : context (TypeCheckContext::get ()), expected (expected), locus (locus),
54 78087 : try_result (CoercionResult::get_error ()), emit_errors (emit_errors),
55 78087 : try_flag (try_flag), is_cast_site (is_cast_site)
56 78087 : {}
57 :
58 : bool
59 78087 : TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
60 : {
61 : // FIXME this is not finished and might be super simplified
62 : // see:
63 : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs
64 :
65 78087 : if (receiver->get_kind () == TyTy::TypeKind::NEVER)
66 : {
67 461 : try_result = coerce_never (receiver);
68 461 : return true;
69 : }
70 :
71 : // unsize
72 77626 : tl::expected<CoercionResult, CoerceUnsizedError> unsize_coercion
73 77626 : = coerce_unsized (receiver, expected);
74 77626 : if (unsize_coercion)
75 : {
76 236 : try_result = unsize_coercion.value ();
77 236 : return true;
78 : }
79 77390 : else if (unsize_coercion.error () == CoerceUnsizedError::Unsafe)
80 : {
81 : // location_t lhs = mappings.lookup_location (receiver->get_ref ());
82 : // location_t rhs = mappings.lookup_location (expected->get_ref ());
83 : // object_unsafe_error (locus, lhs, rhs);
84 : return false;
85 : }
86 :
87 : // pointers
88 77217 : switch (expected->get_kind ())
89 : {
90 7917 : case TyTy::TypeKind::POINTER:
91 7917 : {
92 7917 : auto *ptr = expected->as<TyTy::PointerType> ();
93 7917 : try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ());
94 7917 : return !try_result.is_error ();
95 : }
96 :
97 23105 : case TyTy::TypeKind::REF:
98 23105 : {
99 23105 : auto *ptr = expected->as<TyTy::ReferenceType> ();
100 23105 : try_result
101 23105 : = coerce_borrowed_pointer (receiver, ptr, ptr->mutability ());
102 23105 : return !try_result.is_error ();
103 : }
104 46195 : break;
105 :
106 46195 : default:
107 46195 : break;
108 : }
109 :
110 : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210
111 46195 : switch (receiver->get_kind ())
112 : {
113 46195 : default:
114 46195 : {
115 46195 : rust_debug (
116 : "do_coercion default unify and infer expected: %s receiver %s",
117 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
118 46195 : TyTy::BaseType *result
119 46195 : = unify_site_and (receiver->get_ref (),
120 46195 : TyTy::TyWithLocation (expected),
121 46195 : TyTy::TyWithLocation (receiver),
122 : locus /*unify_locus*/, false /*emit_errors*/,
123 : !try_flag /*commit_if_ok*/, try_flag /*infer*/,
124 : try_flag /*cleanup on error*/);
125 46195 : if (result->get_kind () != TyTy::TypeKind::ERROR)
126 : {
127 36206 : try_result = CoercionResult{{}, result};
128 36206 : return true;
129 : }
130 : }
131 9989 : break;
132 : }
133 :
134 9989 : return !try_result.is_error ();
135 78087 : }
136 :
137 : TypeCoercionRules::CoercionResult
138 461 : TypeCoercionRules::coerce_never (TyTy::BaseType *receiver)
139 : {
140 : // handle never
141 : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L155
142 :
143 : // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
144 : // type variable, we want `?T` to fallback to `!` if not
145 : // otherwise constrained. An example where this arises:
146 : //
147 : // let _: Option<?T> = Some({ return; });
148 : //
149 : // here, we would coerce from `!` to `?T`.
150 461 : if (expected->has_substitutions_defined () && !expected->is_concrete ())
151 : {
152 1 : location_t locus = mappings.lookup_location (receiver->get_ref ());
153 1 : TyTy::TyVar implicit_var = TyTy::TyVar::get_implicit_infer_var (locus);
154 1 : return CoercionResult{{}, implicit_var.get_tyty ()};
155 : }
156 :
157 460 : bool expected_is_infer_var = expected->get_kind () == TyTy::TypeKind::INFER;
158 460 : bool expected_is_general_infer_var
159 : = expected_is_infer_var
160 460 : && (static_cast<TyTy::InferType *> (expected)->get_infer_kind ()
161 460 : == TyTy::InferType::InferTypeKind::GENERAL);
162 :
163 : // FIXME this 'expected_is_general_infer_var' case needs to eventually
164 : // should go away see: compile/never_type_err1.rs
165 : //
166 : // I think we need inference obligations to say that yes we have a
167 : // general inference variable but we add the oligation to the expected
168 : // type that it could default to '!'
169 460 : if (expected_is_general_infer_var)
170 1 : return CoercionResult{{}, receiver};
171 : else
172 459 : return CoercionResult{{}, expected->clone ()};
173 : }
174 :
175 : TypeCoercionRules::CoercionResult
176 7917 : TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver,
177 : TyTy::PointerType *expected,
178 : Mutability to_mutbl)
179 : {
180 7917 : rust_debug ("coerce_unsafe_ptr(receiver={%s}, expected={%s})",
181 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
182 :
183 7917 : Mutability from_mutbl = Mutability::Imm;
184 7917 : TyTy::BaseType *element = nullptr;
185 7917 : switch (receiver->get_kind ())
186 : {
187 4230 : case TyTy::TypeKind::REF:
188 4230 : {
189 4230 : TyTy::ReferenceType *ref
190 : = static_cast<TyTy::ReferenceType *> (receiver);
191 4230 : from_mutbl = ref->mutability ();
192 4230 : element = ref->get_base ();
193 : }
194 4230 : break;
195 :
196 3547 : case TyTy::TypeKind::POINTER:
197 3547 : {
198 3547 : TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver);
199 3547 : from_mutbl = ref->mutability ();
200 3547 : element = ref->get_base ();
201 : }
202 3547 : break;
203 :
204 140 : default:
205 140 : {
206 140 : if (types_compatable (TyTy::TyWithLocation (receiver),
207 140 : TyTy::TyWithLocation (expected), UNKNOWN_LOCATION,
208 : false))
209 0 : return CoercionResult{{}, expected->clone ()};
210 :
211 140 : return CoercionResult::get_error ();
212 : }
213 : }
214 :
215 7777 : bool receiver_is_non_ptr = receiver->get_kind () != TyTy::TypeKind::POINTER;
216 7777 : if (autoderef_flag && receiver_is_non_ptr)
217 : {
218 : // it is unsafe to autoderef to raw pointers
219 14 : return CoercionResult::get_error ();
220 : }
221 :
222 7763 : if (!coerceable_mutability (from_mutbl, to_mutbl))
223 : {
224 0 : location_t lhs = mappings.lookup_location (receiver->get_ref ());
225 0 : location_t rhs = mappings.lookup_location (expected->get_ref ());
226 0 : mismatched_mutability_error (locus, lhs, rhs);
227 0 : return TypeCoercionRules::CoercionResult::get_error ();
228 : }
229 :
230 7763 : TyTy::PointerType *coerced_mutability
231 : = new TyTy::PointerType (receiver->get_ref (),
232 7763 : TyTy::TyVar (element->get_ref ()), to_mutbl);
233 :
234 7763 : rust_debug ("coerce_unsafe_ptr unify-site");
235 :
236 : // this is a really annoying case rust allows casts of any ptr to another ptr
237 : // types
238 : //
239 : // *? vs *i32 - simple coercion valid
240 : // *? vs *T - simple coercion valid
241 : // *i32 vs *i32 - simple coercion valid
242 : // *i32 vs *u8 - simple coercion not valid but allowed in cast site
243 : // *T vs *u8 - not valid but is allowed in cast site
244 :
245 7763 : TyTy::BaseType *result
246 15526 : = unify_site_and (receiver->get_ref (), TyTy::TyWithLocation (expected),
247 7763 : TyTy::TyWithLocation (coerced_mutability),
248 : locus /*unify_locus*/, !try_flag /*emit_errors*/,
249 : !try_flag /*commit_if_ok*/,
250 2308 : try_flag && !is_cast_site /*infer*/,
251 : try_flag /*cleanup on error*/);
252 7763 : bool unsafe_ptr_coerceion_ok = result->get_kind () != TyTy::TypeKind::ERROR;
253 7763 : if (unsafe_ptr_coerceion_ok)
254 7700 : return CoercionResult{{}, result};
255 :
256 63 : return TypeCoercionRules::CoercionResult::get_error ();
257 : }
258 :
259 : /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
260 : /// To match `A` with `B`, autoderef will be performed,
261 : /// calling `deref`/`deref_mut` where necessary.
262 : TypeCoercionRules::CoercionResult
263 23105 : TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
264 : TyTy::ReferenceType *expected,
265 : Mutability to_mutbl)
266 : {
267 23105 : rust_debug ("coerce_borrowed_pointer(a={%s}, b={%s})",
268 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
269 :
270 23105 : Mutability from_mutbl = Mutability::Imm;
271 23105 : switch (receiver->get_kind ())
272 : {
273 10787 : case TyTy::TypeKind::REF:
274 10787 : {
275 10787 : from_mutbl = receiver->as<TyTy::ReferenceType> ()->mutability ();
276 : }
277 10787 : break;
278 12318 : default:
279 12318 : {
280 12318 : rust_debug ("coerce_borrowed_pointer -- unify");
281 12318 : TyTy::BaseType *result
282 12318 : = unify_site_and (receiver->get_ref (),
283 12318 : TyTy::TyWithLocation (receiver),
284 12318 : TyTy::TyWithLocation (expected), locus,
285 : false /*emit_errors*/, !try_flag /*commit_if_ok*/,
286 : try_flag /* infer */,
287 : try_flag /*cleanup_on_failure*/);
288 12318 : bool default_coerceion_ok
289 12318 : = result->get_kind () != TyTy::TypeKind::ERROR;
290 12318 : if (default_coerceion_ok)
291 21 : return CoercionResult{{}, result};
292 :
293 12297 : return TypeCoercionRules::CoercionResult::get_error ();
294 : }
295 : }
296 :
297 10787 : if (!coerceable_mutability (from_mutbl, to_mutbl))
298 : {
299 0 : location_t lhs = mappings.lookup_location (receiver->get_ref ());
300 0 : location_t rhs = mappings.lookup_location (expected->get_ref ());
301 0 : mismatched_mutability_error (locus, lhs, rhs);
302 0 : return TypeCoercionRules::CoercionResult::get_error ();
303 : }
304 :
305 10787 : rust_debug ("coerce_borrowed_pointer -- autoderef cycle");
306 10787 : AutoderefCycle::cycle (receiver);
307 18686 : rust_debug ("coerce_borrowed_pointer -- result: [%s] with adjustments: [%zu]",
308 : try_result.is_error () ? "failed" : "matched",
309 : try_result.adjustments.size ());
310 :
311 10787 : return try_result;
312 : }
313 :
314 : // &[T; n] or &mut [T; n] -> &[T]
315 : // or &mut [T; n] -> &mut [T]
316 : // or &Concrete -> &Trait, etc.
317 : // https://doc.rust-lang.org/stable/reference/type-coercions.html
318 : tl::expected<TypeCoercionRules::CoercionResult,
319 : TypeCoercionRules::CoerceUnsizedError>
320 78036 : TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
321 : TyTy::BaseType *target, bool is_inner)
322 : {
323 78036 : rust_debug ("coerce_unsized(source={%s}, target={%s})",
324 : source->debug_str ().c_str (), target->debug_str ().c_str ());
325 78036 : size_t adjustments_size = adjustments.size ();
326 :
327 78036 : auto setup = unwrap_ptrs_and_refs (source, target);
328 78036 : if (!setup)
329 172 : return tl::unexpected<CoerceUnsizedError> (setup.error ());
330 :
331 : // FIXME
332 : // there is a bunch of code to ensure something is coerce able to a dyn
333 : // trait we need to support but we need to support a few more lang items for
334 : // that see:
335 : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582
336 :
337 77864 : auto a = setup->ty_a;
338 77864 : auto b = setup->ty_b;
339 :
340 77864 : tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result
341 : = tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
342 :
343 77864 : bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
344 77864 : bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
345 :
346 77864 : bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE;
347 77864 : bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY;
348 :
349 77864 : bool expect_adt = b->get_kind () == TyTy::TypeKind::ADT;
350 77864 : bool is_adt = a->get_kind () == TyTy::TypeKind::ADT;
351 :
352 77864 : if (expect_dyn && need_unsize)
353 194 : inner_result
354 196 : = (!setup->unwrapped_pointer && !is_inner)
355 388 : ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
356 194 : : coerce_unsized_dyn (a, b);
357 :
358 77670 : else if (expect_slice && is_array)
359 132 : inner_result
360 139 : = (!setup->unwrapped_pointer && !is_inner)
361 264 : ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
362 132 : : coerce_unsized_array_to_slice (a, b);
363 :
364 77538 : else if (expect_adt && is_adt)
365 3795 : inner_result = coerce_unsized_adt (a, b, setup->needs_reborrow);
366 :
367 77864 : if (!inner_result)
368 : {
369 155214 : adjustments.erase (adjustments.begin () + adjustments_size,
370 77607 : adjustments.end ());
371 77607 : return tl::unexpected<CoerceUnsizedError> (inner_result.error ());
372 : }
373 :
374 257 : TyTy::BaseType *result = inner_result.value ();
375 :
376 257 : if (setup->needs_reborrow)
377 236 : result = apply_reborrow_adjustment (source, target, result,
378 : setup->expected_mutability);
379 :
380 257 : return CoercionResult{adjustments, result};
381 : }
382 :
383 : tl::expected<TypeCoercionRules::CoercionSetup,
384 : TypeCoercionRules::CoerceUnsizedError>
385 78036 : TypeCoercionRules::unwrap_ptrs_and_refs (TyTy::BaseType *source,
386 : TyTy::BaseType *target)
387 : {
388 78036 : bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
389 78036 : bool source_is_ptr = source->get_kind () == TyTy::TypeKind::POINTER;
390 78036 : bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
391 78036 : bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
392 :
393 78036 : bool needs_reborrow = false;
394 78036 : bool unwrapped_pointer = false;
395 78036 : TyTy::BaseType *ty_a = source;
396 78036 : TyTy::BaseType *ty_b = target;
397 78036 : Mutability expected_mutability = Mutability::Imm;
398 78036 : if (source_is_ref && target_is_ref)
399 : {
400 11185 : TyTy::ReferenceType *source_ref
401 : = static_cast<TyTy::ReferenceType *> (source);
402 11185 : TyTy::ReferenceType *target_ref
403 : = static_cast<TyTy::ReferenceType *> (target);
404 :
405 11185 : Mutability from_mutbl = source_ref->mutability ();
406 11185 : Mutability to_mutbl = target_ref->mutability ();
407 11185 : if (!coerceable_mutability (from_mutbl, to_mutbl))
408 : {
409 172 : location_t lhs = mappings.lookup_location (source->get_ref ());
410 172 : location_t rhs = mappings.lookup_location (target->get_ref ());
411 172 : mismatched_mutability_error (locus, lhs, rhs);
412 172 : return tl::unexpected<CoerceUnsizedError> (
413 172 : CoerceUnsizedError::Unsafe);
414 : }
415 :
416 11013 : ty_a = source_ref->get_base ();
417 11013 : ty_b = target_ref->get_base ();
418 11013 : needs_reborrow = true;
419 11013 : unwrapped_pointer = true;
420 11013 : expected_mutability = to_mutbl;
421 :
422 11013 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
423 : source_ref, ty_a);
424 : }
425 66851 : else if (source_is_ref && target_is_ptr)
426 : {
427 4233 : TyTy::ReferenceType *source_ref
428 : = static_cast<TyTy::ReferenceType *> (source);
429 4233 : TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
430 :
431 4233 : Mutability from_mutbl = source_ref->mutability ();
432 4233 : Mutability to_mutbl = target_ref->mutability ();
433 4233 : if (!coerceable_mutability (from_mutbl, to_mutbl))
434 : {
435 0 : location_t lhs = mappings.lookup_location (source->get_ref ());
436 0 : location_t rhs = mappings.lookup_location (target->get_ref ());
437 0 : mismatched_mutability_error (locus, lhs, rhs);
438 0 : return tl::unexpected<CoerceUnsizedError> (
439 0 : CoerceUnsizedError::Unsafe);
440 : }
441 :
442 4233 : ty_a = source_ref->get_base ();
443 4233 : ty_b = target_ref->get_base ();
444 4233 : needs_reborrow = true;
445 4233 : unwrapped_pointer = true;
446 4233 : expected_mutability = to_mutbl;
447 :
448 4233 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
449 : source_ref, ty_a);
450 : }
451 62618 : else if (source_is_ptr && target_is_ptr)
452 : {
453 3555 : TyTy::PointerType *source_ref = static_cast<TyTy::PointerType *> (source);
454 3555 : TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
455 :
456 3555 : Mutability from_mutbl = source_ref->mutability ();
457 3555 : Mutability to_mutbl = target_ref->mutability ();
458 3555 : if (!coerceable_mutability (from_mutbl, to_mutbl))
459 : {
460 0 : location_t lhs = mappings.lookup_location (source->get_ref ());
461 0 : location_t rhs = mappings.lookup_location (target->get_ref ());
462 0 : mismatched_mutability_error (locus, lhs, rhs);
463 0 : return tl::unexpected<CoerceUnsizedError> (
464 0 : CoerceUnsizedError::Unsafe);
465 : }
466 :
467 3555 : ty_a = source_ref->get_base ();
468 3555 : ty_b = target_ref->get_base ();
469 3555 : needs_reborrow = true;
470 3555 : unwrapped_pointer = true;
471 3555 : expected_mutability = to_mutbl;
472 :
473 3555 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
474 : source_ref, ty_a);
475 : }
476 :
477 77864 : return CoercionSetup{ty_a, ty_b, needs_reborrow, expected_mutability,
478 77864 : unwrapped_pointer};
479 : }
480 :
481 : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
482 132 : TypeCoercionRules::coerce_unsized_array_to_slice (TyTy::BaseType *a,
483 : TyTy::BaseType *b)
484 : {
485 132 : auto array_type = static_cast<const TyTy::ArrayType *> (a);
486 132 : auto slice_type = static_cast<const TyTy::SliceType *> (b);
487 :
488 132 : TyTy::BaseType *array_element = array_type->get_element_type ();
489 132 : TyTy::BaseType *slice_element = slice_type->get_element_type ();
490 :
491 132 : if (!array_element->is_equal (*slice_element))
492 89 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
493 :
494 43 : TyTy::BaseType *result = b->clone ();
495 :
496 43 : adjustments.emplace_back (Adjustment::UNSIZE, a, result);
497 :
498 43 : return result;
499 : }
500 : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
501 194 : TypeCoercionRules::coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b)
502 : {
503 194 : bool bounds_compatible = b->bounds_compatible (*a, locus, false);
504 194 : if (!bounds_compatible)
505 1 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe);
506 :
507 : // return the unsize coercion
508 193 : TyTy::BaseType *result = b->clone ();
509 : // result->set_ref (a->get_ref ());
510 :
511 : // append a dyn coercion adjustment
512 193 : adjustments.emplace_back (Adjustment::UNSIZE, a, result);
513 :
514 193 : return result;
515 : }
516 : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
517 3795 : TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
518 : bool needs_reborrow)
519 : {
520 3795 : auto source_adt = static_cast<const TyTy::ADTType *> (a);
521 3795 : auto target_adt = static_cast<const TyTy::ADTType *> (b);
522 :
523 3795 : if ((!source_adt->is_struct_struct () && !source_adt->is_tuple_struct ())
524 2415 : || (!target_adt->is_struct_struct () && !target_adt->is_tuple_struct ())
525 6207 : || (source_adt->get_id () != target_adt->get_id ())
526 6014 : || (source_adt->get_variants ().front ()->num_fields ()
527 2219 : != target_adt->get_variants ().front ()->num_fields ()))
528 1576 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
529 :
530 2219 : auto source_variant = source_adt->get_variants ().front ();
531 2219 : auto target_variant = target_adt->get_variants ().front ();
532 :
533 2219 : TyTy::BaseType *differing_source_field = nullptr;
534 2219 : TyTy::BaseType *differing_target_field = nullptr;
535 2219 : size_t diff_count = 0;
536 2219 : bool is_last_field = false;
537 :
538 6553 : for (size_t i = 0; i < source_variant->num_fields (); i++)
539 : {
540 4334 : auto s_field_raw
541 4334 : = source_variant->get_field_at_index (i)->get_field_type ();
542 4334 : auto t_field_raw
543 4334 : = target_variant->get_field_at_index (i)->get_field_type ();
544 4334 : auto s_field = s_field_raw->contains_infer ()
545 4334 : ? s_field_raw
546 4147 : : s_field_raw->monomorphized_clone ();
547 4334 : auto t_field = t_field_raw->contains_infer ()
548 4334 : ? t_field_raw
549 4256 : : t_field_raw->monomorphized_clone ();
550 :
551 : // https://doc.rust-lang.org/reference/dynamically-sized-types.html
552 4334 : if (!s_field->is_equal (*t_field))
553 : {
554 484 : if (s_field->is<TyTy::ADTType> () && t_field->is<TyTy::ADTType> ())
555 25 : if (auto phantom_data
556 25 : = mappings.lookup_lang_item (LangItem::Kind::PHANTOM_DATA))
557 9 : if (s_field->as<TyTy::ADTType> ()->get_id () == phantom_data
558 9 : && t_field->as<TyTy::ADTType> ()->get_id () == phantom_data)
559 3 : continue;
560 :
561 428 : differing_source_field = s_field;
562 428 : differing_target_field = t_field;
563 428 : diff_count++;
564 428 : is_last_field = (i == source_variant->num_fields () - 1);
565 : }
566 : }
567 :
568 2219 : if (diff_count != 1)
569 1807 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
570 :
571 412 : if (needs_reborrow && !is_last_field)
572 2 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
573 :
574 410 : auto adjustments_size = adjustments.size ();
575 410 : auto inner_coercion
576 410 : = coerce_unsized (differing_source_field, differing_target_field, true);
577 410 : if (!inner_coercion)
578 389 : return tl::unexpected<CoerceUnsizedError> (inner_coercion.error ());
579 42 : adjustments.erase (adjustments.begin () + adjustments_size,
580 21 : adjustments.end ());
581 :
582 21 : TyTy::BaseType *result = b->clone ();
583 21 : adjustments.emplace_back (Adjustment::UNSIZE, a, result);
584 :
585 21 : return result;
586 3795 : }
587 : TyTy::BaseType *
588 236 : TypeCoercionRules::apply_reborrow_adjustment (TyTy::BaseType *source,
589 : TyTy::BaseType *target,
590 : TyTy::BaseType *result,
591 : Mutability expected_mutability)
592 : {
593 236 : TyTy::BaseType *reborrow = nullptr;
594 :
595 236 : if (target->get_kind () == TyTy::TypeKind::POINTER)
596 : {
597 22 : reborrow = new TyTy::PointerType (source->get_ref (),
598 11 : TyTy::TyVar (result->get_ref ()),
599 22 : expected_mutability);
600 : }
601 : else
602 : {
603 450 : reborrow = new TyTy::ReferenceType (source->get_ref (),
604 225 : TyTy::TyVar (result->get_ref ()),
605 450 : expected_mutability);
606 : }
607 :
608 472 : Adjustment::AdjustmentType borrow_type
609 236 : = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF
610 : : Adjustment::MUT_REF;
611 :
612 236 : adjustments.emplace_back (borrow_type, result, reborrow);
613 236 : return reborrow;
614 : }
615 :
616 : bool
617 16991 : TypeCoercionRules::select (TyTy::BaseType &autoderefed)
618 : {
619 16991 : rust_debug ("TypeCoercionRules::select autoderefed={%s} can_eq expected={%s}",
620 : autoderefed.debug_str ().c_str (),
621 : expected->debug_str ().c_str ());
622 :
623 16991 : TyTy::BaseType *result
624 16991 : = unify_site_and (autoderefed.get_ref (), TyTy::TyWithLocation (expected),
625 16991 : TyTy::TyWithLocation (&autoderefed),
626 : UNDEF_LOCATION /* locus */, false /*emit_errors*/,
627 : !try_flag /*commit_if_ok*/, try_flag /*infer*/,
628 : try_flag /*cleanup*/);
629 16991 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
630 16991 : if (!ok)
631 : return false;
632 :
633 7899 : try_result = CoercionResult{adjustments, result};
634 7899 : return true;
635 : }
636 :
637 : /// Coercing a mutable reference to an immutable works, while
638 : /// coercing `&T` to `&mut T` should be forbidden.
639 : bool
640 37523 : TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
641 : Mutability to_mutbl)
642 : {
643 37523 : return to_mutbl == Mutability::Imm || (from_mutbl == to_mutbl);
644 : }
645 :
646 : void
647 172 : TypeCoercionRules::mismatched_mutability_error (location_t expr_locus,
648 : location_t lhs, location_t rhs)
649 : {
650 172 : if (!emit_errors)
651 : return;
652 :
653 1 : rich_location r (line_table, expr_locus);
654 1 : r.add_range (lhs);
655 1 : r.add_range (rhs);
656 1 : rust_error_at (r, "mismatched mutability");
657 1 : }
658 :
659 : void
660 0 : TypeCoercionRules::object_unsafe_error (location_t expr_locus, location_t lhs,
661 : location_t rhs)
662 : {
663 0 : if (!emit_errors)
664 : return;
665 :
666 0 : rich_location r (line_table, expr_locus);
667 0 : r.add_range (lhs);
668 0 : r.add_range (rhs);
669 0 : rust_error_at (r, "unsafe unsize coercion");
670 0 : }
671 :
672 : } // namespace Resolver
673 : } // namespace Rust
|