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