]>
Commit | Line | Data |
---|---|---|
2b03887a FG |
1 | //! Check properties that are required by built-in traits and set |
2 | //! up data structures required by type-checking/codegen. | |
3 | ||
781aab86 FG |
4 | use crate::errors; |
5 | ||
353b0b11 | 6 | use rustc_data_structures::fx::FxHashSet; |
781aab86 | 7 | use rustc_errors::{ErrorGuaranteed, MultiSpan}; |
2b03887a FG |
8 | use rustc_hir as hir; |
9 | use rustc_hir::def_id::{DefId, LocalDefId}; | |
10 | use rustc_hir::lang_items::LangItem; | |
11 | use rustc_hir::ItemKind; | |
2b03887a | 12 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
e8be2606 | 13 | use rustc_infer::infer::TyCtxtInferExt; |
9c376795 | 14 | use rustc_infer::infer::{self, RegionResolutionError}; |
353b0b11 | 15 | use rustc_infer::traits::Obligation; |
2b03887a | 16 | use rustc_middle::ty::adjustment::CoerceUnsizedInfo; |
31ef2f64 | 17 | use rustc_middle::ty::print::PrintTraitRefExt as _; |
9ffffee4 | 18 | use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; |
c620b35d | 19 | use rustc_span::{Span, DUMMY_SP}; |
2b03887a | 20 | use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; |
9c376795 | 21 | use rustc_trait_selection::traits::misc::{ |
49aad941 FG |
22 | type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, |
23 | ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, | |
9c376795 | 24 | }; |
353b0b11 | 25 | use rustc_trait_selection::traits::ObligationCtxt; |
2b03887a FG |
26 | use rustc_trait_selection::traits::{self, ObligationCause}; |
27 | use std::collections::BTreeMap; | |
28 | ||
c620b35d FG |
29 | pub(super) fn check_trait<'tcx>( |
30 | tcx: TyCtxt<'tcx>, | |
31 | trait_def_id: DefId, | |
32 | impl_def_id: LocalDefId, | |
33 | impl_header: ty::ImplTraitHeader<'tcx>, | |
34 | ) -> Result<(), ErrorGuaranteed> { | |
2b03887a | 35 | let lang_items = tcx.lang_items(); |
c620b35d | 36 | let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; |
c0240ec0 FG |
37 | let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); |
38 | res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); | |
39 | res = res.and( | |
40 | checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty), | |
41 | ); | |
42 | res = res.and( | |
43 | checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), | |
44 | ); | |
45 | res.and( | |
46 | checker | |
47 | .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), | |
48 | ) | |
2b03887a FG |
49 | } |
50 | ||
51 | struct Checker<'tcx> { | |
52 | tcx: TyCtxt<'tcx>, | |
53 | trait_def_id: DefId, | |
c620b35d FG |
54 | impl_def_id: LocalDefId, |
55 | impl_header: ty::ImplTraitHeader<'tcx>, | |
2b03887a FG |
56 | } |
57 | ||
58 | impl<'tcx> Checker<'tcx> { | |
c620b35d FG |
59 | fn check( |
60 | &self, | |
61 | trait_def_id: Option<DefId>, | |
62 | f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>, | |
63 | ) -> Result<(), ErrorGuaranteed> { | |
64 | if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) } | |
2b03887a FG |
65 | } |
66 | } | |
67 | ||
c620b35d FG |
68 | fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
69 | let tcx = checker.tcx; | |
70 | let impl_did = checker.impl_def_id; | |
2b03887a | 71 | // Destructors only work on local ADT types. |
c620b35d | 72 | match checker.impl_header.trait_ref.instantiate_identity().self_ty().kind() { |
c0240ec0 FG |
73 | ty::Adt(def, _) if def.did().is_local() => return Ok(()), |
74 | ty::Error(_) => return Ok(()), | |
2b03887a FG |
75 | _ => {} |
76 | } | |
77 | ||
9ffffee4 | 78 | let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); |
2b03887a | 79 | |
c0240ec0 | 80 | Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span })) |
2b03887a FG |
81 | } |
82 | ||
c620b35d FG |
83 | fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
84 | let tcx = checker.tcx; | |
85 | let impl_header = checker.impl_header; | |
86 | let impl_did = checker.impl_def_id; | |
2b03887a FG |
87 | debug!("visit_implementation_of_copy: impl_did={:?}", impl_did); |
88 | ||
c620b35d | 89 | let self_type = impl_header.trait_ref.instantiate_identity().self_ty(); |
2b03887a FG |
90 | debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); |
91 | ||
92 | let param_env = tcx.param_env(impl_did); | |
93 | assert!(!self_type.has_escaping_bound_vars()); | |
94 | ||
95 | debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); | |
96 | ||
c620b35d FG |
97 | if let ty::ImplPolarity::Negative = impl_header.polarity { |
98 | return Ok(()); | |
99 | } | |
2b03887a | 100 | |
c620b35d | 101 | let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); |
9c376795 | 102 | match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { |
c0240ec0 | 103 | Ok(()) => Ok(()), |
49aad941 | 104 | Err(CopyImplementationError::InfringingFields(fields)) => { |
c620b35d | 105 | let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; |
c0240ec0 | 106 | Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span)) |
2b03887a FG |
107 | } |
108 | Err(CopyImplementationError::NotAnAdt) => { | |
c620b35d | 109 | let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; |
c0240ec0 | 110 | Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span })) |
2b03887a FG |
111 | } |
112 | Err(CopyImplementationError::HasDestructor) => { | |
c620b35d | 113 | let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; |
c0240ec0 | 114 | Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span })) |
2b03887a FG |
115 | } |
116 | } | |
117 | } | |
118 | ||
c620b35d FG |
119 | fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
120 | let tcx = checker.tcx; | |
121 | let header = checker.impl_header; | |
122 | let impl_did = checker.impl_def_id; | |
123 | let self_type = header.trait_ref.instantiate_identity().self_ty(); | |
49aad941 FG |
124 | assert!(!self_type.has_escaping_bound_vars()); |
125 | ||
126 | let param_env = tcx.param_env(impl_did); | |
127 | ||
c620b35d FG |
128 | if let ty::ImplPolarity::Negative = header.polarity { |
129 | return Ok(()); | |
130 | } | |
49aad941 | 131 | |
c620b35d | 132 | let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); |
49aad941 | 133 | match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { |
c0240ec0 | 134 | Ok(()) => Ok(()), |
49aad941 | 135 | Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { |
c620b35d | 136 | let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; |
c0240ec0 | 137 | Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span)) |
49aad941 FG |
138 | } |
139 | Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { | |
c620b35d | 140 | let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; |
c0240ec0 | 141 | Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) |
49aad941 FG |
142 | } |
143 | } | |
144 | } | |
145 | ||
c620b35d FG |
146 | fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
147 | let tcx = checker.tcx; | |
148 | let impl_did = checker.impl_def_id; | |
2b03887a FG |
149 | debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); |
150 | ||
151 | // Just compute this for the side-effects, in particular reporting | |
152 | // errors; other parts of the code may demand it for the info of | |
153 | // course. | |
154 | let span = tcx.def_span(impl_did); | |
c0240ec0 | 155 | tcx.at(span).ensure().coerce_unsized_info(impl_did) |
2b03887a FG |
156 | } |
157 | ||
c620b35d FG |
158 | fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { |
159 | let tcx = checker.tcx; | |
160 | let impl_did = checker.impl_def_id; | |
161 | let trait_ref = checker.impl_header.trait_ref.instantiate_identity(); | |
2b03887a FG |
162 | debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); |
163 | ||
9ffffee4 | 164 | let span = tcx.def_span(impl_did); |
2b03887a FG |
165 | |
166 | let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); | |
167 | ||
c620b35d | 168 | let source = trait_ref.self_ty(); |
2b03887a FG |
169 | assert!(!source.has_escaping_bound_vars()); |
170 | let target = { | |
2b03887a FG |
171 | assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); |
172 | ||
add651ee | 173 | trait_ref.args.type_at(1) |
2b03887a FG |
174 | }; |
175 | ||
176 | debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target); | |
177 | ||
178 | let param_env = tcx.param_env(impl_did); | |
179 | ||
2b03887a | 180 | let infcx = tcx.infer_ctxt().build(); |
9ffffee4 | 181 | let cause = ObligationCause::misc(span, impl_did); |
2b03887a | 182 | |
781aab86 FG |
183 | // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw |
184 | // pointers. This is enforced here: we only allow impls for references, raw pointers, and things | |
185 | // that are effectively repr(transparent) newtypes around types that already hav a | |
186 | // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some | |
187 | // of them support an allocator, but we ensure that for the cases where the type implements this | |
188 | // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else | |
189 | // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) | |
190 | // even if they do not carry that attribute. | |
ed00b5ec | 191 | use rustc_type_ir::TyKind::*; |
2b03887a | 192 | match (source.kind(), target.kind()) { |
e8be2606 | 193 | (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if r_a == *r_b && mutbl_a == *mutbl_b => { |
c0240ec0 FG |
194 | Ok(()) |
195 | } | |
e8be2606 | 196 | (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()), |
add651ee | 197 | (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => { |
2b03887a FG |
198 | if def_a != def_b { |
199 | let source_path = tcx.def_path_str(def_a.did()); | |
200 | let target_path = tcx.def_path_str(def_b.did()); | |
201 | ||
c0240ec0 | 202 | return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion { |
781aab86 FG |
203 | span, |
204 | trait_name: "DispatchFromDyn", | |
205 | note: true, | |
206 | source_path, | |
207 | target_path, | |
c0240ec0 | 208 | })); |
2b03887a FG |
209 | } |
210 | ||
c0240ec0 | 211 | let mut res = Ok(()); |
2b03887a | 212 | if def_a.repr().c() || def_a.repr().packed() { |
c0240ec0 | 213 | res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span })); |
2b03887a FG |
214 | } |
215 | ||
216 | let fields = &def_a.non_enum_variant().fields; | |
217 | ||
218 | let coerced_fields = fields | |
219 | .iter() | |
220 | .filter(|field| { | |
add651ee FG |
221 | let ty_a = field.ty(tcx, args_a); |
222 | let ty_b = field.ty(tcx, args_b); | |
2b03887a FG |
223 | |
224 | if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { | |
781aab86 FG |
225 | if layout.is_1zst() { |
226 | // ignore 1-ZST fields | |
2b03887a FG |
227 | return false; |
228 | } | |
229 | } | |
230 | ||
e8be2606 FG |
231 | if ty_a == ty_b { |
232 | res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST { | |
233 | span, | |
234 | name: field.name, | |
235 | ty: ty_a, | |
236 | })); | |
2b03887a | 237 | |
e8be2606 | 238 | return false; |
2b03887a FG |
239 | } |
240 | ||
241 | return true; | |
242 | }) | |
243 | .collect::<Vec<_>>(); | |
244 | ||
245 | if coerced_fields.is_empty() { | |
c0240ec0 | 246 | res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle { |
781aab86 FG |
247 | span, |
248 | trait_name: "DispatchFromDyn", | |
249 | note: true, | |
c0240ec0 | 250 | })); |
2b03887a | 251 | } else if coerced_fields.len() > 1 { |
c0240ec0 | 252 | res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti { |
781aab86 FG |
253 | span, |
254 | coercions_note: true, | |
255 | number: coerced_fields.len(), | |
256 | coercions: coerced_fields | |
257 | .iter() | |
258 | .map(|field| { | |
259 | format!( | |
260 | "`{}` (`{}` to `{}`)", | |
261 | field.name, | |
262 | field.ty(tcx, args_a), | |
263 | field.ty(tcx, args_b), | |
264 | ) | |
265 | }) | |
266 | .collect::<Vec<_>>() | |
267 | .join(", "), | |
c0240ec0 | 268 | })); |
2b03887a | 269 | } else { |
31ef2f64 | 270 | let ocx = ObligationCtxt::new_with_diagnostics(&infcx); |
353b0b11 FG |
271 | for field in coerced_fields { |
272 | ocx.register_obligation(Obligation::new( | |
273 | tcx, | |
274 | cause.clone(), | |
275 | param_env, | |
49aad941 FG |
276 | ty::TraitRef::new( |
277 | tcx, | |
2b03887a | 278 | dispatch_from_dyn_trait, |
add651ee | 279 | [field.ty(tcx, args_a), field.ty(tcx, args_b)], |
49aad941 | 280 | ), |
353b0b11 FG |
281 | )); |
282 | } | |
283 | let errors = ocx.select_all_or_error(); | |
2b03887a | 284 | if !errors.is_empty() { |
c0240ec0 | 285 | res = Err(infcx.err_ctxt().report_fulfillment_errors(errors)); |
2b03887a FG |
286 | } |
287 | ||
288 | // Finally, resolve all regions. | |
289 | let outlives_env = OutlivesEnvironment::new(param_env); | |
c0240ec0 | 290 | res = res.and(ocx.resolve_regions_and_report_errors(impl_did, &outlives_env)); |
2b03887a | 291 | } |
c0240ec0 | 292 | res |
2b03887a | 293 | } |
c0240ec0 FG |
294 | _ => Err(tcx |
295 | .dcx() | |
296 | .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })), | |
2b03887a FG |
297 | } |
298 | } | |
299 | ||
c0240ec0 FG |
300 | pub fn coerce_unsized_info<'tcx>( |
301 | tcx: TyCtxt<'tcx>, | |
302 | impl_did: LocalDefId, | |
303 | ) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> { | |
2b03887a | 304 | debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); |
2b03887a FG |
305 | let span = tcx.def_span(impl_did); |
306 | ||
307 | let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); | |
308 | ||
49aad941 | 309 | let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); |
2b03887a | 310 | |
add651ee FG |
311 | let source = tcx.type_of(impl_did).instantiate_identity(); |
312 | let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); | |
2b03887a | 313 | assert_eq!(trait_ref.def_id, coerce_unsized_trait); |
add651ee | 314 | let target = trait_ref.args.type_at(1); |
2b03887a FG |
315 | debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); |
316 | ||
317 | let param_env = tcx.param_env(impl_did); | |
318 | assert!(!source.has_escaping_bound_vars()); | |
319 | ||
2b03887a FG |
320 | debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); |
321 | ||
322 | let infcx = tcx.infer_ctxt().build(); | |
9ffffee4 | 323 | let cause = ObligationCause::misc(span, impl_did); |
2b03887a FG |
324 | let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, |
325 | mt_b: ty::TypeAndMut<'tcx>, | |
326 | mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { | |
487cf647 | 327 | if mt_a.mutbl < mt_b.mutbl { |
2b03887a FG |
328 | infcx |
329 | .err_ctxt() | |
330 | .report_mismatched_types( | |
331 | &cause, | |
332 | mk_ptr(mt_b.ty), | |
333 | target, | |
334 | ty::error::TypeError::Mutability, | |
335 | ) | |
336 | .emit(); | |
337 | } | |
338 | (mt_a.ty, mt_b.ty, unsize_trait, None) | |
339 | }; | |
340 | let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { | |
341 | (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { | |
342 | infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); | |
343 | let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; | |
344 | let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; | |
fe692bf9 | 345 | check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) |
2b03887a FG |
346 | } |
347 | ||
e8be2606 FG |
348 | (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl( |
349 | ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }, | |
350 | ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }, | |
351 | &|ty| Ty::new_imm_ptr(tcx, ty), | |
352 | ), | |
2b03887a | 353 | |
e8be2606 FG |
354 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl( |
355 | ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }, | |
356 | ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }, | |
357 | &|ty| Ty::new_imm_ptr(tcx, ty), | |
358 | ), | |
2b03887a | 359 | |
add651ee | 360 | (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b)) |
2b03887a FG |
361 | if def_a.is_struct() && def_b.is_struct() => |
362 | { | |
363 | if def_a != def_b { | |
364 | let source_path = tcx.def_path_str(def_a.did()); | |
365 | let target_path = tcx.def_path_str(def_b.did()); | |
c0240ec0 | 366 | return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame { |
2b03887a | 367 | span, |
781aab86 FG |
368 | trait_name: "CoerceUnsized", |
369 | note: true, | |
2b03887a | 370 | source_path, |
781aab86 | 371 | target_path, |
c0240ec0 | 372 | })); |
2b03887a FG |
373 | } |
374 | ||
375 | // Here we are considering a case of converting | |
9ffffee4 | 376 | // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`, |
2b03887a FG |
377 | // which acts like a pointer to `U`, but carries along some extra data of type `T`: |
378 | // | |
379 | // struct Foo<T, U> { | |
380 | // extra: T, | |
381 | // ptr: *mut U, | |
382 | // } | |
383 | // | |
384 | // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized | |
385 | // to `Foo<T, [i32]>`. That impl would look like: | |
386 | // | |
387 | // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {} | |
388 | // | |
389 | // Here `U = [i32; 3]` and `V = [i32]`. At runtime, | |
390 | // when this coercion occurs, we would be changing the | |
391 | // field `ptr` from a thin pointer of type `*mut [i32; | |
392 | // 3]` to a fat pointer of type `*mut [i32]` (with | |
9c376795 | 393 | // extra data `3`). **The purpose of this check is to |
2b03887a FG |
394 | // make sure that we know how to do this conversion.** |
395 | // | |
396 | // To check if this impl is legal, we would walk down | |
397 | // the fields of `Foo` and consider their types with | |
c620b35d | 398 | // both generic parameters. We are looking to find that |
2b03887a FG |
399 | // exactly one (non-phantom) field has changed its |
400 | // type, which we will expect to be the pointer that | |
401 | // is becoming fat (we could probably generalize this | |
402 | // to multiple thin pointers of the same type becoming | |
403 | // fat, but we don't). In this case: | |
404 | // | |
405 | // - `extra` has type `T` before and type `T` after | |
406 | // - `ptr` has type `*mut U` before and type `*mut V` after | |
407 | // | |
408 | // Since just one field changed, we would then check | |
409 | // that `*mut U: CoerceUnsized<*mut V>` is implemented | |
410 | // (in other words, that we know how to do this | |
411 | // conversion). This will work out because `U: | |
412 | // Unsize<V>`, and we have a builtin rule that `*mut | |
413 | // U` can be coerced to `*mut V` if `U: Unsize<V>`. | |
414 | let fields = &def_a.non_enum_variant().fields; | |
415 | let diff_fields = fields | |
353b0b11 | 416 | .iter_enumerated() |
2b03887a | 417 | .filter_map(|(i, f)| { |
add651ee | 418 | let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b)); |
2b03887a | 419 | |
add651ee | 420 | if tcx.type_of(f.did).instantiate_identity().is_phantom_data() { |
2b03887a FG |
421 | // Ignore PhantomData fields |
422 | return None; | |
423 | } | |
424 | ||
425 | // Ignore fields that aren't changed; it may | |
426 | // be that we could get away with subtyping or | |
427 | // something more accepting, but we use | |
428 | // equality because we want to be able to | |
429 | // perform this check without computing | |
e8be2606 FG |
430 | // variance or constraining opaque types' hidden types. |
431 | // (This is because we may have to evaluate constraint | |
2b03887a FG |
432 | // expressions in the course of execution.) |
433 | // See e.g., #41936. | |
e8be2606 FG |
434 | if a == b { |
435 | return None; | |
2b03887a FG |
436 | } |
437 | ||
438 | // Collect up all fields that were significantly changed | |
439 | // i.e., those that contain T in coerce_unsized T -> U | |
440 | Some((i, a, b)) | |
441 | }) | |
442 | .collect::<Vec<_>>(); | |
443 | ||
444 | if diff_fields.is_empty() { | |
c0240ec0 | 445 | return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField { |
2b03887a | 446 | span, |
781aab86 FG |
447 | trait_name: "CoerceUnsized", |
448 | note: true, | |
c0240ec0 | 449 | })); |
2b03887a FG |
450 | } else if diff_fields.len() > 1 { |
451 | let item = tcx.hir().expect_item(impl_did); | |
9c376795 FG |
452 | let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind { |
453 | t.path.span | |
454 | } else { | |
455 | tcx.def_span(impl_did) | |
456 | }; | |
2b03887a | 457 | |
c0240ec0 | 458 | return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti { |
2b03887a | 459 | span, |
781aab86 FG |
460 | coercions_note: true, |
461 | number: diff_fields.len(), | |
462 | coercions: diff_fields | |
2b03887a | 463 | .iter() |
781aab86 | 464 | .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)) |
2b03887a | 465 | .collect::<Vec<_>>() |
781aab86 | 466 | .join(", "), |
c0240ec0 | 467 | })); |
2b03887a FG |
468 | } |
469 | ||
470 | let (i, a, b) = diff_fields[0]; | |
471 | let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); | |
472 | (a, b, coerce_unsized_trait, Some(kind)) | |
473 | } | |
474 | ||
475 | _ => { | |
c0240ec0 FG |
476 | return Err(tcx |
477 | .dcx() | |
478 | .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" })); | |
2b03887a FG |
479 | } |
480 | }; | |
481 | ||
482 | // Register an obligation for `A: Trait<B>`. | |
31ef2f64 | 483 | let ocx = ObligationCtxt::new_with_diagnostics(&infcx); |
9ffffee4 | 484 | let cause = traits::ObligationCause::misc(span, impl_did); |
49aad941 FG |
485 | let obligation = Obligation::new( |
486 | tcx, | |
487 | cause, | |
488 | param_env, | |
489 | ty::TraitRef::new(tcx, trait_def_id, [source, target]), | |
490 | ); | |
353b0b11 FG |
491 | ocx.register_obligation(obligation); |
492 | let errors = ocx.select_all_or_error(); | |
2b03887a | 493 | if !errors.is_empty() { |
ed00b5ec | 494 | infcx.err_ctxt().report_fulfillment_errors(errors); |
2b03887a FG |
495 | } |
496 | ||
497 | // Finally, resolve all regions. | |
498 | let outlives_env = OutlivesEnvironment::new(param_env); | |
353b0b11 | 499 | let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env); |
2b03887a | 500 | |
c0240ec0 | 501 | Ok(CoerceUnsizedInfo { custom_kind: kind }) |
2b03887a | 502 | } |
49aad941 FG |
503 | |
504 | fn infringing_fields_error( | |
505 | tcx: TyCtxt<'_>, | |
506 | fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>, | |
507 | lang_item: LangItem, | |
508 | impl_did: LocalDefId, | |
509 | impl_span: Span, | |
510 | ) -> ErrorGuaranteed { | |
511 | let trait_did = tcx.require_lang_item(lang_item, Some(impl_span)); | |
512 | ||
513 | let trait_name = tcx.def_path_str(trait_did); | |
514 | ||
49aad941 FG |
515 | // We'll try to suggest constraining type parameters to fulfill the requirements of |
516 | // their `Copy` implementation. | |
517 | let mut errors: BTreeMap<_, Vec<_>> = Default::default(); | |
518 | let mut bounds = vec![]; | |
519 | ||
520 | let mut seen_tys = FxHashSet::default(); | |
521 | ||
781aab86 FG |
522 | let mut label_spans = Vec::new(); |
523 | ||
49aad941 FG |
524 | for (field, ty, reason) in fields { |
525 | // Only report an error once per type. | |
526 | if !seen_tys.insert(ty) { | |
527 | continue; | |
528 | } | |
529 | ||
781aab86 | 530 | label_spans.push(tcx.def_span(field.did)); |
49aad941 FG |
531 | |
532 | match reason { | |
533 | InfringingFieldsReason::Fulfill(fulfillment_errors) => { | |
534 | for error in fulfillment_errors { | |
535 | let error_predicate = error.obligation.predicate; | |
536 | // Only note if it's not the root obligation, otherwise it's trivial and | |
537 | // should be self-explanatory (i.e. a field literally doesn't implement Copy). | |
538 | ||
539 | // FIXME: This error could be more descriptive, especially if the error_predicate | |
540 | // contains a foreign type or if it's a deeply nested type... | |
541 | if error_predicate != error.root_obligation.predicate { | |
542 | errors | |
543 | .entry((ty.to_string(), error_predicate.to_string())) | |
544 | .or_default() | |
545 | .push(error.obligation.cause.span); | |
546 | } | |
fe692bf9 | 547 | if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { |
49aad941 | 548 | trait_ref, |
e8be2606 | 549 | polarity: ty::PredicatePolarity::Positive, |
49aad941 FG |
550 | .. |
551 | })) = error_predicate.kind().skip_binder() | |
552 | { | |
553 | let ty = trait_ref.self_ty(); | |
554 | if let ty::Param(_) = ty.kind() { | |
555 | bounds.push(( | |
556 | format!("{ty}"), | |
31ef2f64 | 557 | trait_ref.print_trait_sugared().to_string(), |
49aad941 FG |
558 | Some(trait_ref.def_id), |
559 | )); | |
560 | } | |
561 | } | |
562 | } | |
563 | } | |
564 | InfringingFieldsReason::Regions(region_errors) => { | |
565 | for error in region_errors { | |
566 | let ty = ty.to_string(); | |
567 | match error { | |
568 | RegionResolutionError::ConcreteFailure(origin, a, b) => { | |
569 | let predicate = format!("{b}: {a}"); | |
570 | errors | |
571 | .entry((ty.clone(), predicate.clone())) | |
572 | .or_default() | |
573 | .push(origin.span()); | |
4b012472 | 574 | if let ty::RegionKind::ReEarlyParam(ebr) = *b |
ed00b5ec FG |
575 | && ebr.has_name() |
576 | { | |
577 | bounds.push((b.to_string(), a.to_string(), None)); | |
578 | } | |
49aad941 FG |
579 | } |
580 | RegionResolutionError::GenericBoundFailure(origin, a, b) => { | |
581 | let predicate = format!("{a}: {b}"); | |
582 | errors | |
583 | .entry((ty.clone(), predicate.clone())) | |
584 | .or_default() | |
585 | .push(origin.span()); | |
586 | if let infer::region_constraints::GenericKind::Param(_) = a { | |
587 | bounds.push((a.to_string(), b.to_string(), None)); | |
588 | } | |
589 | } | |
590 | _ => continue, | |
591 | } | |
592 | } | |
593 | } | |
594 | } | |
595 | } | |
781aab86 | 596 | let mut notes = Vec::new(); |
49aad941 FG |
597 | for ((ty, error_predicate), spans) in errors { |
598 | let span: MultiSpan = spans.into(); | |
781aab86 | 599 | notes.push(errors::ImplForTyRequires { |
49aad941 | 600 | span, |
781aab86 FG |
601 | error_predicate, |
602 | trait_name: trait_name.clone(), | |
603 | ty, | |
604 | }); | |
49aad941 | 605 | } |
781aab86 | 606 | |
c0240ec0 | 607 | let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy { |
781aab86 FG |
608 | span: impl_span, |
609 | trait_name, | |
610 | label_spans, | |
611 | notes, | |
612 | }); | |
613 | ||
49aad941 FG |
614 | suggest_constraining_type_params( |
615 | tcx, | |
616 | tcx.hir().get_generics(impl_did).expect("impls always have generics"), | |
617 | &mut err, | |
618 | bounds | |
619 | .iter() | |
620 | .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)), | |
621 | None, | |
622 | ); | |
623 | ||
624 | err.emit() | |
625 | } |