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 45445 : TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected,
28 : location_t locus, bool allow_autoderef,
29 : bool is_cast_site)
30 : {
31 45445 : TypeCoercionRules resolver (expected, locus, true, allow_autoderef, false,
32 45445 : is_cast_site);
33 45445 : bool ok = resolver.do_coercion (receiver);
34 90835 : return ok ? resolver.try_result : CoercionResult::get_error ();
35 45445 : }
36 :
37 : TypeCoercionRules::CoercionResult
38 27800 : TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
39 : TyTy::BaseType *expected, location_t locus,
40 : bool allow_autoderef, bool is_cast_site)
41 : {
42 27800 : TypeCoercionRules resolver (expected, locus, false, allow_autoderef, true,
43 27800 : is_cast_site);
44 27800 : bool ok = resolver.do_coercion (receiver);
45 38074 : return ok ? resolver.try_result : CoercionResult::get_error ();
46 27800 : }
47 :
48 73245 : 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 146490 : : AutoderefCycle (!allow_autoderef), mappings (Analysis::Mappings::get ()),
53 73245 : context (TypeCheckContext::get ()), expected (expected), locus (locus),
54 73245 : try_result (CoercionResult::get_error ()), emit_errors (emit_errors),
55 73245 : try_flag (try_flag), is_cast_site (is_cast_site)
56 73245 : {}
57 :
58 : bool
59 73245 : 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 73245 : if (receiver->get_kind () == TyTy::TypeKind::NEVER)
66 : {
67 484 : try_result = coerce_never (receiver);
68 484 : return true;
69 : }
70 :
71 : // unsize
72 72761 : tl::expected<CoercionResult, CoerceUnsizedError> unsize_coercion
73 72761 : = coerce_unsized (receiver, expected);
74 72761 : if (unsize_coercion)
75 : {
76 236 : try_result = unsize_coercion.value ();
77 236 : return true;
78 : }
79 72525 : 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 72352 : switch (expected->get_kind ())
89 : {
90 8108 : case TyTy::TypeKind::POINTER:
91 8108 : {
92 8108 : auto *ptr = expected->as<TyTy::PointerType> ();
93 8108 : try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ());
94 8108 : return !try_result.is_error ();
95 : }
96 :
97 13637 : case TyTy::TypeKind::REF:
98 13637 : {
99 13637 : auto *ptr = expected->as<TyTy::ReferenceType> ();
100 13637 : try_result
101 13637 : = coerce_borrowed_pointer (receiver, ptr, ptr->mutability ());
102 13637 : return !try_result.is_error ();
103 : }
104 50607 : break;
105 :
106 50607 : default:
107 50607 : break;
108 : }
109 :
110 : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210
111 50607 : switch (receiver->get_kind ())
112 : {
113 50607 : default:
114 50607 : {
115 50607 : 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 50607 : TyTy::BaseType *result
119 50607 : = unify_site_and (receiver->get_ref (),
120 50607 : TyTy::TyWithLocation (expected),
121 50607 : 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 50607 : if (result->get_kind () != TyTy::TypeKind::ERROR)
126 : {
127 38953 : try_result = CoercionResult{{}, result};
128 38953 : return true;
129 : }
130 : }
131 11654 : break;
132 : }
133 :
134 11654 : return !try_result.is_error ();
135 73245 : }
136 :
137 : TypeCoercionRules::CoercionResult
138 484 : 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 484 : 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 483 : bool expected_is_infer_var = expected->get_kind () == TyTy::TypeKind::INFER;
158 483 : bool expected_is_general_infer_var
159 : = expected_is_infer_var
160 483 : && (static_cast<TyTy::InferType *> (expected)->get_infer_kind ()
161 483 : == 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 483 : if (expected_is_general_infer_var)
170 1 : return CoercionResult{{}, receiver};
171 : else
172 482 : return CoercionResult{{}, expected->clone ()};
173 : }
174 :
175 : TypeCoercionRules::CoercionResult
176 8108 : TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver,
177 : TyTy::PointerType *expected,
178 : Mutability to_mutbl)
179 : {
180 8108 : rust_debug ("coerce_unsafe_ptr(receiver={%s}, expected={%s})",
181 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
182 :
183 8108 : Mutability from_mutbl = Mutability::Imm;
184 8108 : TyTy::BaseType *element = nullptr;
185 8108 : switch (receiver->get_kind ())
186 : {
187 4316 : case TyTy::TypeKind::REF:
188 4316 : {
189 4316 : TyTy::ReferenceType *ref
190 : = static_cast<TyTy::ReferenceType *> (receiver);
191 4316 : from_mutbl = ref->mutability ();
192 4316 : element = ref->get_base ();
193 : }
194 4316 : break;
195 :
196 3792 : case TyTy::TypeKind::POINTER:
197 3792 : {
198 3792 : TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver);
199 3792 : from_mutbl = ref->mutability ();
200 3792 : element = ref->get_base ();
201 : }
202 3792 : break;
203 :
204 0 : default:
205 0 : {
206 0 : if (types_compatable (TyTy::TyWithLocation (receiver),
207 0 : TyTy::TyWithLocation (expected), UNKNOWN_LOCATION,
208 : false))
209 0 : return CoercionResult{{}, expected->clone ()};
210 :
211 0 : return CoercionResult::get_error ();
212 : }
213 : }
214 :
215 8108 : bool receiver_is_non_ptr = receiver->get_kind () != TyTy::TypeKind::POINTER;
216 8108 : 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 8094 : 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 8094 : TyTy::PointerType *coerced_mutability
231 : = new TyTy::PointerType (receiver->get_ref (),
232 8094 : TyTy::TyVar (element->get_ref ()), to_mutbl);
233 :
234 8094 : 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 8094 : TyTy::BaseType *result
246 16188 : = unify_site_and (receiver->get_ref (), TyTy::TyWithLocation (expected),
247 8094 : TyTy::TyWithLocation (coerced_mutability),
248 : locus /*unify_locus*/, !try_flag /*emit_errors*/,
249 : !try_flag /*commit_if_ok*/,
250 2367 : try_flag && !is_cast_site /*infer*/,
251 : try_flag /*cleanup on error*/);
252 8094 : bool unsafe_ptr_coerceion_ok = result->get_kind () != TyTy::TypeKind::ERROR;
253 8094 : if (unsafe_ptr_coerceion_ok)
254 8031 : 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 13637 : TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver,
264 : TyTy::ReferenceType *expected,
265 : Mutability to_mutbl)
266 : {
267 13637 : rust_debug ("coerce_borrowed_pointer(a={%s}, b={%s})",
268 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
269 :
270 13637 : Mutability from_mutbl = Mutability::Imm;
271 13637 : switch (receiver->get_kind ())
272 : {
273 11825 : case TyTy::TypeKind::REF:
274 11825 : {
275 11825 : from_mutbl = receiver->as<TyTy::ReferenceType> ()->mutability ();
276 : }
277 11825 : break;
278 1812 : default:
279 1812 : {
280 1812 : rust_debug ("coerce_borrowed_pointer -- unify");
281 1812 : TyTy::BaseType *result
282 1812 : = unify_site_and (receiver->get_ref (),
283 1812 : TyTy::TyWithLocation (receiver),
284 1812 : TyTy::TyWithLocation (expected), locus,
285 : false /*emit_errors*/, !try_flag /*commit_if_ok*/,
286 : try_flag /* infer */,
287 : try_flag /*cleanup_on_failure*/);
288 1812 : bool default_coerceion_ok
289 1812 : = result->get_kind () != TyTy::TypeKind::ERROR;
290 1812 : if (default_coerceion_ok)
291 29 : return CoercionResult{{}, result};
292 :
293 1783 : return TypeCoercionRules::CoercionResult::get_error ();
294 : }
295 : }
296 :
297 11825 : 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 11825 : rust_debug ("coerce_borrowed_pointer -- autoderef cycle");
306 11825 : AutoderefCycle::cycle (receiver);
307 11825 : rust_debug ("coerce_borrowed_pointer -- result: [%s] with adjustments: [%zu]",
308 : try_result.is_error () ? "failed" : "matched",
309 : try_result.adjustments.size ());
310 :
311 11825 : 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 73172 : TypeCoercionRules::coerce_unsized (TyTy::BaseType *source,
321 : TyTy::BaseType *target, bool is_inner)
322 : {
323 73172 : rust_debug ("coerce_unsized(source={%s}, target={%s})",
324 : source->debug_str ().c_str (), target->debug_str ().c_str ());
325 73172 : size_t adjustments_size = adjustments.size ();
326 :
327 73172 : auto setup = unwrap_ptrs_and_refs (source, target);
328 73172 : 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 73000 : auto a = setup->ty_a;
338 73000 : auto b = setup->ty_b;
339 :
340 73000 : tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result
341 : = tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
342 :
343 73000 : bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC;
344 73000 : bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC;
345 :
346 73000 : bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE;
347 73000 : bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY;
348 :
349 73000 : bool expect_adt = b->get_kind () == TyTy::TypeKind::ADT;
350 73000 : bool is_adt = a->get_kind () == TyTy::TypeKind::ADT;
351 :
352 73000 : 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 72806 : else if (expect_slice && is_array)
359 133 : inner_result
360 140 : = (!setup->unwrapped_pointer && !is_inner)
361 266 : ? tl::unexpected<CoerceUnsizedError> (inner_result.error ())
362 133 : : coerce_unsized_array_to_slice (a, b);
363 :
364 72673 : else if (expect_adt && is_adt)
365 3877 : inner_result = coerce_unsized_adt (a, b, setup->needs_reborrow);
366 :
367 73000 : if (!inner_result)
368 : {
369 145486 : adjustments.erase (adjustments.begin () + adjustments_size,
370 72743 : adjustments.end ());
371 72743 : 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 73172 : TypeCoercionRules::unwrap_ptrs_and_refs (TyTy::BaseType *source,
386 : TyTy::BaseType *target)
387 : {
388 73172 : bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF;
389 73172 : bool source_is_ptr = source->get_kind () == TyTy::TypeKind::POINTER;
390 73172 : bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF;
391 73172 : bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER;
392 :
393 73172 : bool needs_reborrow = false;
394 73172 : bool unwrapped_pointer = false;
395 73172 : TyTy::BaseType *ty_a = source;
396 73172 : TyTy::BaseType *ty_b = target;
397 73172 : Mutability expected_mutability = Mutability::Imm;
398 73172 : if (source_is_ref && target_is_ref)
399 : {
400 12223 : TyTy::ReferenceType *source_ref
401 : = static_cast<TyTy::ReferenceType *> (source);
402 12223 : TyTy::ReferenceType *target_ref
403 : = static_cast<TyTy::ReferenceType *> (target);
404 :
405 12223 : Mutability from_mutbl = source_ref->mutability ();
406 12223 : Mutability to_mutbl = target_ref->mutability ();
407 12223 : 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 12051 : ty_a = source_ref->get_base ();
417 12051 : ty_b = target_ref->get_base ();
418 12051 : needs_reborrow = true;
419 12051 : unwrapped_pointer = true;
420 12051 : expected_mutability = to_mutbl;
421 :
422 12051 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
423 : source_ref, ty_a);
424 : }
425 60949 : else if (source_is_ref && target_is_ptr)
426 : {
427 4319 : TyTy::ReferenceType *source_ref
428 : = static_cast<TyTy::ReferenceType *> (source);
429 4319 : TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
430 :
431 4319 : Mutability from_mutbl = source_ref->mutability ();
432 4319 : Mutability to_mutbl = target_ref->mutability ();
433 4319 : 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 4319 : ty_a = source_ref->get_base ();
443 4319 : ty_b = target_ref->get_base ();
444 4319 : needs_reborrow = true;
445 4319 : unwrapped_pointer = true;
446 4319 : expected_mutability = to_mutbl;
447 :
448 4319 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
449 : source_ref, ty_a);
450 : }
451 56630 : else if (source_is_ptr && target_is_ptr)
452 : {
453 3800 : TyTy::PointerType *source_ref = static_cast<TyTy::PointerType *> (source);
454 3800 : TyTy::PointerType *target_ref = static_cast<TyTy::PointerType *> (target);
455 :
456 3800 : Mutability from_mutbl = source_ref->mutability ();
457 3800 : Mutability to_mutbl = target_ref->mutability ();
458 3800 : 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 3800 : ty_a = source_ref->get_base ();
468 3800 : ty_b = target_ref->get_base ();
469 3800 : needs_reborrow = true;
470 3800 : unwrapped_pointer = true;
471 3800 : expected_mutability = to_mutbl;
472 :
473 3800 : adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION,
474 : source_ref, ty_a);
475 : }
476 :
477 73000 : return CoercionSetup{ty_a, ty_b, needs_reborrow, expected_mutability,
478 73000 : unwrapped_pointer};
479 : }
480 :
481 : tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError>
482 133 : TypeCoercionRules::coerce_unsized_array_to_slice (TyTy::BaseType *a,
483 : TyTy::BaseType *b)
484 : {
485 133 : auto array_type = static_cast<const TyTy::ArrayType *> (a);
486 133 : auto slice_type = static_cast<const TyTy::SliceType *> (b);
487 :
488 133 : TyTy::BaseType *array_element = array_type->get_element_type ();
489 133 : TyTy::BaseType *slice_element = slice_type->get_element_type ();
490 :
491 133 : if (!array_element->is_equal (*slice_element))
492 90 : 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 3877 : TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b,
518 : bool needs_reborrow)
519 : {
520 3877 : auto source_adt = static_cast<const TyTy::ADTType *> (a);
521 3877 : auto target_adt = static_cast<const TyTy::ADTType *> (b);
522 :
523 3877 : if ((!source_adt->is_struct_struct () && !source_adt->is_tuple_struct ())
524 2401 : || (!target_adt->is_struct_struct () && !target_adt->is_tuple_struct ())
525 6275 : || (source_adt->get_id () != target_adt->get_id ())
526 6096 : || (source_adt->get_variants ().front ()->num_fields ()
527 2219 : != target_adt->get_variants ().front ()->num_fields ()))
528 1658 : 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 6554 : for (size_t i = 0; i < source_variant->num_fields (); i++)
539 : {
540 4335 : auto s_field_raw
541 4335 : = source_variant->get_field_at_index (i)->get_field_type ();
542 4335 : auto t_field_raw
543 4335 : = target_variant->get_field_at_index (i)->get_field_type ();
544 4335 : auto s_field = s_field_raw->contains_infer ()
545 4335 : ? s_field_raw
546 4148 : : s_field_raw->monomorphized_clone ();
547 4335 : auto t_field = t_field_raw->contains_infer ()
548 4335 : ? t_field_raw
549 4257 : : t_field_raw->monomorphized_clone ();
550 :
551 : // https://doc.rust-lang.org/reference/dynamically-sized-types.html
552 4335 : if (!s_field->is_equal (*t_field))
553 : {
554 485 : 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 429 : differing_source_field = s_field;
562 429 : differing_target_field = t_field;
563 429 : diff_count++;
564 429 : is_last_field = (i == source_variant->num_fields () - 1);
565 : }
566 : }
567 :
568 2219 : if (diff_count != 1)
569 1806 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
570 :
571 413 : if (needs_reborrow && !is_last_field)
572 2 : return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular);
573 :
574 411 : auto adjustments_size = adjustments.size ();
575 411 : auto inner_coercion
576 411 : = coerce_unsized (differing_source_field, differing_target_field, true);
577 411 : if (!inner_coercion)
578 390 : 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 3877 : }
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 20276 : TypeCoercionRules::select (TyTy::BaseType &autoderefed)
618 : {
619 20276 : rust_debug ("TypeCoercionRules::select autoderefed={%s} can_eq expected={%s}",
620 : autoderefed.debug_str ().c_str (),
621 : expected->debug_str ().c_str ());
622 :
623 20276 : TyTy::BaseType *result
624 20276 : = unify_site_and (autoderefed.get_ref (), TyTy::TyWithLocation (expected),
625 20276 : TyTy::TyWithLocation (&autoderefed),
626 : UNDEF_LOCATION /* locus */, false /*emit_errors*/,
627 : !try_flag /*commit_if_ok*/, try_flag /*infer*/,
628 : try_flag /*cleanup*/);
629 20276 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
630 20276 : if (!ok)
631 : return false;
632 :
633 7931 : try_result = CoercionResult{adjustments, result};
634 7931 : 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 40261 : TypeCoercionRules::coerceable_mutability (Mutability from_mutbl,
641 : Mutability to_mutbl)
642 : {
643 40261 : 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
|