]>
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 | ||
4 | use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem}; | |
5 | use rustc_errors::{struct_span_err, MultiSpan}; | |
6 | use rustc_hir as hir; | |
7 | use rustc_hir::def_id::{DefId, LocalDefId}; | |
8 | use rustc_hir::lang_items::LangItem; | |
9 | use rustc_hir::ItemKind; | |
10 | use rustc_infer::infer; | |
11 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; | |
12 | use rustc_infer::infer::TyCtxtInferExt; | |
13 | use rustc_middle::ty::adjustment::CoerceUnsizedInfo; | |
14 | use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable}; | |
15 | use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; | |
16 | use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; | |
17 | use rustc_trait_selection::traits::predicate_for_trait_def; | |
18 | use rustc_trait_selection::traits::{self, ObligationCause}; | |
19 | use std::collections::BTreeMap; | |
20 | ||
21 | pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { | |
22 | let lang_items = tcx.lang_items(); | |
23 | Checker { tcx, trait_def_id } | |
24 | .check(lang_items.drop_trait(), visit_implementation_of_drop) | |
25 | .check(lang_items.copy_trait(), visit_implementation_of_copy) | |
26 | .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized) | |
27 | .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn); | |
28 | } | |
29 | ||
30 | struct Checker<'tcx> { | |
31 | tcx: TyCtxt<'tcx>, | |
32 | trait_def_id: DefId, | |
33 | } | |
34 | ||
35 | impl<'tcx> Checker<'tcx> { | |
36 | fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self | |
37 | where | |
38 | F: FnMut(TyCtxt<'tcx>, LocalDefId), | |
39 | { | |
40 | if Some(self.trait_def_id) == trait_def_id { | |
41 | for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) { | |
42 | f(self.tcx, impl_def_id); | |
43 | } | |
44 | } | |
45 | self | |
46 | } | |
47 | } | |
48 | ||
49 | fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { | |
50 | // Destructors only work on local ADT types. | |
51 | match tcx.type_of(impl_did).kind() { | |
52 | ty::Adt(def, _) if def.did().is_local() => return, | |
53 | ty::Error(_) => return, | |
54 | _ => {} | |
55 | } | |
56 | ||
57 | let sp = match tcx.hir().expect_item(impl_did).kind { | |
58 | ItemKind::Impl(ref impl_) => impl_.self_ty.span, | |
59 | _ => bug!("expected Drop impl item"), | |
60 | }; | |
61 | ||
62 | tcx.sess.emit_err(DropImplOnWrongItem { span: sp }); | |
63 | } | |
64 | ||
65 | fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { | |
66 | debug!("visit_implementation_of_copy: impl_did={:?}", impl_did); | |
67 | ||
68 | let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); | |
69 | ||
70 | let self_type = tcx.type_of(impl_did); | |
71 | debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); | |
72 | ||
73 | let param_env = tcx.param_env(impl_did); | |
74 | assert!(!self_type.has_escaping_bound_vars()); | |
75 | ||
76 | debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); | |
77 | ||
78 | let span = match tcx.hir().expect_item(impl_did).kind { | |
79 | ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return, | |
80 | ItemKind::Impl(impl_) => impl_.self_ty.span, | |
81 | _ => bug!("expected Copy impl item"), | |
82 | }; | |
83 | ||
84 | let cause = traits::ObligationCause::misc(span, impl_hir_id); | |
85 | match can_type_implement_copy(tcx, param_env, self_type, cause) { | |
86 | Ok(()) => {} | |
87 | Err(CopyImplementationError::InfrigingFields(fields)) => { | |
88 | let mut err = struct_span_err!( | |
89 | tcx.sess, | |
90 | span, | |
91 | E0204, | |
92 | "the trait `Copy` may not be implemented for this type" | |
93 | ); | |
94 | ||
95 | // We'll try to suggest constraining type parameters to fulfill the requirements of | |
96 | // their `Copy` implementation. | |
97 | let mut errors: BTreeMap<_, Vec<_>> = Default::default(); | |
98 | let mut bounds = vec![]; | |
99 | ||
100 | for (field, ty) in fields { | |
101 | let field_span = tcx.def_span(field.did); | |
102 | let field_ty_span = match tcx.hir().get_if_local(field.did) { | |
103 | Some(hir::Node::Field(field_def)) => field_def.ty.span, | |
104 | _ => field_span, | |
105 | }; | |
106 | err.span_label(field_span, "this field does not implement `Copy`"); | |
107 | // Spin up a new FulfillmentContext, so we can get the _precise_ reason | |
108 | // why this field does not implement Copy. This is useful because sometimes | |
109 | // it is not immediately clear why Copy is not implemented for a field, since | |
110 | // all we point at is the field itself. | |
111 | let infcx = tcx.infer_ctxt().ignoring_regions().build(); | |
112 | for error in traits::fully_solve_bound( | |
113 | &infcx, | |
114 | traits::ObligationCause::dummy_with_span(field_ty_span), | |
115 | param_env, | |
116 | ty, | |
487cf647 | 117 | tcx.require_lang_item(LangItem::Copy, Some(span)), |
2b03887a FG |
118 | ) { |
119 | let error_predicate = error.obligation.predicate; | |
120 | // Only note if it's not the root obligation, otherwise it's trivial and | |
121 | // should be self-explanatory (i.e. a field literally doesn't implement Copy). | |
122 | ||
123 | // FIXME: This error could be more descriptive, especially if the error_predicate | |
124 | // contains a foreign type or if it's a deeply nested type... | |
125 | if error_predicate != error.root_obligation.predicate { | |
126 | errors | |
127 | .entry((ty.to_string(), error_predicate.to_string())) | |
128 | .or_default() | |
129 | .push(error.obligation.cause.span); | |
130 | } | |
487cf647 | 131 | if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { |
2b03887a FG |
132 | trait_ref, |
133 | polarity: ty::ImplPolarity::Positive, | |
134 | .. | |
487cf647 | 135 | })) = error_predicate.kind().skip_binder() |
2b03887a FG |
136 | { |
137 | let ty = trait_ref.self_ty(); | |
138 | if let ty::Param(_) = ty.kind() { | |
139 | bounds.push(( | |
140 | format!("{ty}"), | |
141 | trait_ref.print_only_trait_path().to_string(), | |
142 | Some(trait_ref.def_id), | |
143 | )); | |
144 | } | |
145 | } | |
146 | } | |
147 | } | |
148 | for ((ty, error_predicate), spans) in errors { | |
149 | let span: MultiSpan = spans.into(); | |
150 | err.span_note( | |
151 | span, | |
152 | &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate), | |
153 | ); | |
154 | } | |
155 | suggest_constraining_type_params( | |
156 | tcx, | |
157 | tcx.hir().get_generics(impl_did).expect("impls always have generics"), | |
158 | &mut err, | |
159 | bounds.iter().map(|(param, constraint, def_id)| { | |
160 | (param.as_str(), constraint.as_str(), *def_id) | |
161 | }), | |
162 | ); | |
163 | err.emit(); | |
164 | } | |
165 | Err(CopyImplementationError::NotAnAdt) => { | |
166 | tcx.sess.emit_err(CopyImplOnNonAdt { span }); | |
167 | } | |
168 | Err(CopyImplementationError::HasDestructor) => { | |
169 | tcx.sess.emit_err(CopyImplOnTypeWithDtor { span }); | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) { | |
175 | debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); | |
176 | ||
177 | // Just compute this for the side-effects, in particular reporting | |
178 | // errors; other parts of the code may demand it for the info of | |
179 | // course. | |
180 | let span = tcx.def_span(impl_did); | |
181 | tcx.at(span).coerce_unsized_info(impl_did); | |
182 | } | |
183 | ||
184 | fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) { | |
185 | debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); | |
186 | ||
187 | let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); | |
188 | let span = tcx.hir().span(impl_hir_id); | |
189 | ||
190 | let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); | |
191 | ||
192 | let source = tcx.type_of(impl_did); | |
193 | assert!(!source.has_escaping_bound_vars()); | |
194 | let target = { | |
195 | let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); | |
196 | assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); | |
197 | ||
198 | trait_ref.substs.type_at(1) | |
199 | }; | |
200 | ||
201 | debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target); | |
202 | ||
203 | let param_env = tcx.param_env(impl_did); | |
204 | ||
205 | let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg); | |
206 | ||
207 | let infcx = tcx.infer_ctxt().build(); | |
208 | let cause = ObligationCause::misc(span, impl_hir_id); | |
209 | ||
210 | use rustc_type_ir::sty::TyKind::*; | |
211 | match (source.kind(), target.kind()) { | |
212 | (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) | |
213 | if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} | |
214 | (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), | |
215 | (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) | |
216 | if def_a.is_struct() && def_b.is_struct() => | |
217 | { | |
218 | if def_a != def_b { | |
219 | let source_path = tcx.def_path_str(def_a.did()); | |
220 | let target_path = tcx.def_path_str(def_b.did()); | |
221 | ||
222 | create_err(&format!( | |
223 | "the trait `DispatchFromDyn` may only be implemented \ | |
224 | for a coercion between structures with the same \ | |
225 | definition; expected `{}`, found `{}`", | |
226 | source_path, target_path, | |
227 | )) | |
228 | .emit(); | |
229 | ||
230 | return; | |
231 | } | |
232 | ||
233 | if def_a.repr().c() || def_a.repr().packed() { | |
234 | create_err( | |
235 | "structs implementing `DispatchFromDyn` may not have \ | |
236 | `#[repr(packed)]` or `#[repr(C)]`", | |
237 | ) | |
238 | .emit(); | |
239 | } | |
240 | ||
241 | let fields = &def_a.non_enum_variant().fields; | |
242 | ||
243 | let coerced_fields = fields | |
244 | .iter() | |
245 | .filter(|field| { | |
246 | let ty_a = field.ty(tcx, substs_a); | |
247 | let ty_b = field.ty(tcx, substs_b); | |
248 | ||
249 | if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { | |
250 | if layout.is_zst() && layout.align.abi.bytes() == 1 { | |
251 | // ignore ZST fields with alignment of 1 byte | |
252 | return false; | |
253 | } | |
254 | } | |
255 | ||
256 | if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { | |
257 | if ok.obligations.is_empty() { | |
258 | create_err( | |
259 | "the trait `DispatchFromDyn` may only be implemented \ | |
260 | for structs containing the field being coerced, \ | |
261 | ZST fields with 1 byte alignment, and nothing else", | |
262 | ) | |
263 | .note(&format!( | |
264 | "extra field `{}` of type `{}` is not allowed", | |
265 | field.name, ty_a, | |
266 | )) | |
267 | .emit(); | |
268 | ||
269 | return false; | |
270 | } | |
271 | } | |
272 | ||
273 | return true; | |
274 | }) | |
275 | .collect::<Vec<_>>(); | |
276 | ||
277 | if coerced_fields.is_empty() { | |
278 | create_err( | |
279 | "the trait `DispatchFromDyn` may only be implemented \ | |
280 | for a coercion between structures with a single field \ | |
281 | being coerced, none found", | |
282 | ) | |
283 | .emit(); | |
284 | } else if coerced_fields.len() > 1 { | |
285 | create_err("implementing the `DispatchFromDyn` trait requires multiple coercions") | |
286 | .note( | |
287 | "the trait `DispatchFromDyn` may only be implemented \ | |
288 | for a coercion between structures with a single field \ | |
289 | being coerced", | |
290 | ) | |
291 | .note(&format!( | |
292 | "currently, {} fields need coercions: {}", | |
293 | coerced_fields.len(), | |
294 | coerced_fields | |
295 | .iter() | |
296 | .map(|field| { | |
297 | format!( | |
298 | "`{}` (`{}` to `{}`)", | |
299 | field.name, | |
300 | field.ty(tcx, substs_a), | |
301 | field.ty(tcx, substs_b), | |
302 | ) | |
303 | }) | |
304 | .collect::<Vec<_>>() | |
305 | .join(", ") | |
306 | )) | |
307 | .emit(); | |
308 | } else { | |
309 | let errors = traits::fully_solve_obligations( | |
310 | &infcx, | |
311 | coerced_fields.into_iter().map(|field| { | |
312 | predicate_for_trait_def( | |
313 | tcx, | |
314 | param_env, | |
315 | cause.clone(), | |
316 | dispatch_from_dyn_trait, | |
317 | 0, | |
487cf647 | 318 | [field.ty(tcx, substs_a), field.ty(tcx, substs_b)], |
2b03887a FG |
319 | ) |
320 | }), | |
321 | ); | |
322 | if !errors.is_empty() { | |
487cf647 | 323 | infcx.err_ctxt().report_fulfillment_errors(&errors, None); |
2b03887a FG |
324 | } |
325 | ||
326 | // Finally, resolve all regions. | |
327 | let outlives_env = OutlivesEnvironment::new(param_env); | |
328 | infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); | |
329 | } | |
330 | } | |
331 | _ => { | |
332 | create_err( | |
333 | "the trait `DispatchFromDyn` may only be implemented \ | |
334 | for a coercion between structures", | |
335 | ) | |
336 | .emit(); | |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { | |
342 | debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); | |
343 | ||
344 | // this provider should only get invoked for local def-ids | |
345 | let impl_did = impl_did.expect_local(); | |
346 | let span = tcx.def_span(impl_did); | |
347 | ||
348 | let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); | |
349 | ||
350 | let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { | |
351 | tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string())); | |
352 | }); | |
353 | ||
354 | let source = tcx.type_of(impl_did); | |
355 | let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); | |
356 | assert_eq!(trait_ref.def_id, coerce_unsized_trait); | |
357 | let target = trait_ref.substs.type_at(1); | |
358 | debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); | |
359 | ||
360 | let param_env = tcx.param_env(impl_did); | |
361 | assert!(!source.has_escaping_bound_vars()); | |
362 | ||
363 | let err_info = CoerceUnsizedInfo { custom_kind: None }; | |
364 | ||
365 | debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); | |
366 | ||
367 | let infcx = tcx.infer_ctxt().build(); | |
368 | let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); | |
369 | let cause = ObligationCause::misc(span, impl_hir_id); | |
370 | let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, | |
371 | mt_b: ty::TypeAndMut<'tcx>, | |
372 | mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { | |
487cf647 | 373 | if mt_a.mutbl < mt_b.mutbl { |
2b03887a FG |
374 | infcx |
375 | .err_ctxt() | |
376 | .report_mismatched_types( | |
377 | &cause, | |
378 | mk_ptr(mt_b.ty), | |
379 | target, | |
380 | ty::error::TypeError::Mutability, | |
381 | ) | |
382 | .emit(); | |
383 | } | |
384 | (mt_a.ty, mt_b.ty, unsize_trait, None) | |
385 | }; | |
386 | let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { | |
387 | (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { | |
388 | infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); | |
389 | let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; | |
390 | let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; | |
391 | check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) | |
392 | } | |
393 | ||
394 | (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { | |
395 | let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; | |
396 | check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) | |
397 | } | |
398 | ||
399 | (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)), | |
400 | ||
401 | (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) | |
402 | if def_a.is_struct() && def_b.is_struct() => | |
403 | { | |
404 | if def_a != def_b { | |
405 | let source_path = tcx.def_path_str(def_a.did()); | |
406 | let target_path = tcx.def_path_str(def_b.did()); | |
407 | struct_span_err!( | |
408 | tcx.sess, | |
409 | span, | |
410 | E0377, | |
411 | "the trait `CoerceUnsized` may only be implemented \ | |
412 | for a coercion between structures with the same \ | |
413 | definition; expected `{}`, found `{}`", | |
414 | source_path, | |
415 | target_path | |
416 | ) | |
417 | .emit(); | |
418 | return err_info; | |
419 | } | |
420 | ||
421 | // Here we are considering a case of converting | |
422 | // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`, | |
423 | // which acts like a pointer to `U`, but carries along some extra data of type `T`: | |
424 | // | |
425 | // struct Foo<T, U> { | |
426 | // extra: T, | |
427 | // ptr: *mut U, | |
428 | // } | |
429 | // | |
430 | // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized | |
431 | // to `Foo<T, [i32]>`. That impl would look like: | |
432 | // | |
433 | // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {} | |
434 | // | |
435 | // Here `U = [i32; 3]` and `V = [i32]`. At runtime, | |
436 | // when this coercion occurs, we would be changing the | |
437 | // field `ptr` from a thin pointer of type `*mut [i32; | |
438 | // 3]` to a fat pointer of type `*mut [i32]` (with | |
439 | // extra data `3`). **The purpose of this check is to | |
440 | // make sure that we know how to do this conversion.** | |
441 | // | |
442 | // To check if this impl is legal, we would walk down | |
443 | // the fields of `Foo` and consider their types with | |
444 | // both substitutes. We are looking to find that | |
445 | // exactly one (non-phantom) field has changed its | |
446 | // type, which we will expect to be the pointer that | |
447 | // is becoming fat (we could probably generalize this | |
448 | // to multiple thin pointers of the same type becoming | |
449 | // fat, but we don't). In this case: | |
450 | // | |
451 | // - `extra` has type `T` before and type `T` after | |
452 | // - `ptr` has type `*mut U` before and type `*mut V` after | |
453 | // | |
454 | // Since just one field changed, we would then check | |
455 | // that `*mut U: CoerceUnsized<*mut V>` is implemented | |
456 | // (in other words, that we know how to do this | |
457 | // conversion). This will work out because `U: | |
458 | // Unsize<V>`, and we have a builtin rule that `*mut | |
459 | // U` can be coerced to `*mut V` if `U: Unsize<V>`. | |
460 | let fields = &def_a.non_enum_variant().fields; | |
461 | let diff_fields = fields | |
462 | .iter() | |
463 | .enumerate() | |
464 | .filter_map(|(i, f)| { | |
465 | let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); | |
466 | ||
467 | if tcx.type_of(f.did).is_phantom_data() { | |
468 | // Ignore PhantomData fields | |
469 | return None; | |
470 | } | |
471 | ||
472 | // Ignore fields that aren't changed; it may | |
473 | // be that we could get away with subtyping or | |
474 | // something more accepting, but we use | |
475 | // equality because we want to be able to | |
476 | // perform this check without computing | |
477 | // variance where possible. (This is because | |
478 | // we may have to evaluate constraint | |
479 | // expressions in the course of execution.) | |
480 | // See e.g., #41936. | |
481 | if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { | |
482 | if ok.obligations.is_empty() { | |
483 | return None; | |
484 | } | |
485 | } | |
486 | ||
487 | // Collect up all fields that were significantly changed | |
488 | // i.e., those that contain T in coerce_unsized T -> U | |
489 | Some((i, a, b)) | |
490 | }) | |
491 | .collect::<Vec<_>>(); | |
492 | ||
493 | if diff_fields.is_empty() { | |
494 | struct_span_err!( | |
495 | tcx.sess, | |
496 | span, | |
497 | E0374, | |
498 | "the trait `CoerceUnsized` may only be implemented \ | |
499 | for a coercion between structures with one field \ | |
500 | being coerced, none found" | |
501 | ) | |
502 | .emit(); | |
503 | return err_info; | |
504 | } else if diff_fields.len() > 1 { | |
505 | let item = tcx.hir().expect_item(impl_did); | |
506 | let span = | |
507 | if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind { | |
508 | t.path.span | |
509 | } else { | |
510 | tcx.def_span(impl_did) | |
511 | }; | |
512 | ||
513 | struct_span_err!( | |
514 | tcx.sess, | |
515 | span, | |
516 | E0375, | |
517 | "implementing the trait \ | |
518 | `CoerceUnsized` requires multiple \ | |
519 | coercions" | |
520 | ) | |
521 | .note( | |
522 | "`CoerceUnsized` may only be implemented for \ | |
523 | a coercion between structures with one field being coerced", | |
524 | ) | |
525 | .note(&format!( | |
526 | "currently, {} fields need coercions: {}", | |
527 | diff_fields.len(), | |
528 | diff_fields | |
529 | .iter() | |
530 | .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) }) | |
531 | .collect::<Vec<_>>() | |
532 | .join(", ") | |
533 | )) | |
534 | .span_label(span, "requires multiple coercions") | |
535 | .emit(); | |
536 | return err_info; | |
537 | } | |
538 | ||
539 | let (i, a, b) = diff_fields[0]; | |
540 | let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); | |
541 | (a, b, coerce_unsized_trait, Some(kind)) | |
542 | } | |
543 | ||
544 | _ => { | |
545 | struct_span_err!( | |
546 | tcx.sess, | |
547 | span, | |
548 | E0376, | |
549 | "the trait `CoerceUnsized` may only be implemented \ | |
550 | for a coercion between structures" | |
551 | ) | |
552 | .emit(); | |
553 | return err_info; | |
554 | } | |
555 | }; | |
556 | ||
557 | // Register an obligation for `A: Trait<B>`. | |
558 | let cause = traits::ObligationCause::misc(span, impl_hir_id); | |
559 | let predicate = | |
487cf647 | 560 | predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); |
2b03887a FG |
561 | let errors = traits::fully_solve_obligation(&infcx, predicate); |
562 | if !errors.is_empty() { | |
487cf647 | 563 | infcx.err_ctxt().report_fulfillment_errors(&errors, None); |
2b03887a FG |
564 | } |
565 | ||
566 | // Finally, resolve all regions. | |
567 | let outlives_env = OutlivesEnvironment::new(param_env); | |
568 | infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); | |
569 | ||
570 | CoerceUnsizedInfo { custom_kind: kind } | |
571 | } |