1 //! Check properties that are required by built-in traits and set
2 //! up data structures required by type-checking/codegen.
6 use rustc_data_structures
::fx
::FxHashSet
;
7 use rustc_errors
::{ErrorGuaranteed, MultiSpan}
;
9 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
10 use rustc_hir
::lang_items
::LangItem
;
11 use rustc_hir
::ItemKind
;
12 use rustc_infer
::infer
::outlives
::env
::OutlivesEnvironment
;
13 use rustc_infer
::infer
::TyCtxtInferExt
;
14 use rustc_infer
::infer
::{self, RegionResolutionError}
;
15 use rustc_infer
::traits
::Obligation
;
16 use rustc_middle
::ty
::adjustment
::CoerceUnsizedInfo
;
17 use rustc_middle
::ty
::print
::PrintTraitRefExt
as _
;
18 use rustc_middle
::ty
::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}
;
19 use rustc_span
::{Span, DUMMY_SP}
;
20 use rustc_trait_selection
::traits
::error_reporting
::TypeErrCtxtExt
;
21 use rustc_trait_selection
::traits
::misc
::{
22 type_allowed_to_implement_const_param_ty
, type_allowed_to_implement_copy
,
23 ConstParamTyImplementationError
, CopyImplementationError
, InfringingFieldsReason
,
25 use rustc_trait_selection
::traits
::ObligationCtxt
;
26 use rustc_trait_selection
::traits
::{self, ObligationCause}
;
27 use std
::collections
::BTreeMap
;
29 pub(super) fn check_trait
<'tcx
>(
32 impl_def_id
: LocalDefId
,
33 impl_header
: ty
::ImplTraitHeader
<'tcx
>,
34 ) -> Result
<(), ErrorGuaranteed
> {
35 let lang_items
= tcx
.lang_items();
36 let checker
= Checker { tcx, trait_def_id, impl_def_id, impl_header }
;
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
));
40 checker
.check(lang_items
.const_param_ty_trait(), visit_implementation_of_const_param_ty
),
43 checker
.check(lang_items
.coerce_unsized_trait(), visit_implementation_of_coerce_unsized
),
47 .check(lang_items
.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn
),
51 struct Checker
<'tcx
> {
54 impl_def_id
: LocalDefId
,
55 impl_header
: ty
::ImplTraitHeader
<'tcx
>,
58 impl<'tcx
> Checker
<'tcx
> {
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(()) }
68 fn visit_implementation_of_drop(checker
: &Checker
<'_
>) -> Result
<(), ErrorGuaranteed
> {
69 let tcx
= checker
.tcx
;
70 let impl_did
= checker
.impl_def_id
;
71 // Destructors only work on local ADT types.
72 match checker
.impl_header
.trait_ref
.instantiate_identity().self_ty().kind() {
73 ty
::Adt(def
, _
) if def
.did().is_local() => return Ok(()),
74 ty
::Error(_
) => return Ok(()),
78 let impl_
= tcx
.hir().expect_item(impl_did
).expect_impl();
80 Err(tcx
.dcx().emit_err(errors
::DropImplOnWrongItem { span: impl_.self_ty.span }
))
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
;
87 debug
!("visit_implementation_of_copy: impl_did={:?}", impl_did
);
89 let self_type
= impl_header
.trait_ref
.instantiate_identity().self_ty();
90 debug
!("visit_implementation_of_copy: self_type={:?} (bound)", self_type
);
92 let param_env
= tcx
.param_env(impl_did
);
93 assert
!(!self_type
.has_escaping_bound_vars());
95 debug
!("visit_implementation_of_copy: self_type={:?} (free)", self_type
);
97 if let ty
::ImplPolarity
::Negative
= impl_header
.polarity
{
101 let cause
= traits
::ObligationCause
::misc(DUMMY_SP
, impl_did
);
102 match type_allowed_to_implement_copy(tcx
, param_env
, self_type
, cause
) {
104 Err(CopyImplementationError
::InfringingFields(fields
)) => {
105 let span
= tcx
.hir().expect_item(impl_did
).expect_impl().self_ty
.span
;
106 Err(infringing_fields_error(tcx
, fields
, LangItem
::Copy
, impl_did
, span
))
108 Err(CopyImplementationError
::NotAnAdt
) => {
109 let span
= tcx
.hir().expect_item(impl_did
).expect_impl().self_ty
.span
;
110 Err(tcx
.dcx().emit_err(errors
::CopyImplOnNonAdt { span }
))
112 Err(CopyImplementationError
::HasDestructor
) => {
113 let span
= tcx
.hir().expect_item(impl_did
).expect_impl().self_ty
.span
;
114 Err(tcx
.dcx().emit_err(errors
::CopyImplOnTypeWithDtor { span }
))
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();
124 assert
!(!self_type
.has_escaping_bound_vars());
126 let param_env
= tcx
.param_env(impl_did
);
128 if let ty
::ImplPolarity
::Negative
= header
.polarity
{
132 let cause
= traits
::ObligationCause
::misc(DUMMY_SP
, impl_did
);
133 match type_allowed_to_implement_const_param_ty(tcx
, param_env
, self_type
, cause
) {
135 Err(ConstParamTyImplementationError
::InfrigingFields(fields
)) => {
136 let span
= tcx
.hir().expect_item(impl_did
).expect_impl().self_ty
.span
;
137 Err(infringing_fields_error(tcx
, fields
, LangItem
::ConstParamTy
, impl_did
, span
))
139 Err(ConstParamTyImplementationError
::NotAnAdtOrBuiltinAllowed
) => {
140 let span
= tcx
.hir().expect_item(impl_did
).expect_impl().self_ty
.span
;
141 Err(tcx
.dcx().emit_err(errors
::ConstParamTyImplOnNonAdt { span }
))
146 fn visit_implementation_of_coerce_unsized(checker
: &Checker
<'_
>) -> Result
<(), ErrorGuaranteed
> {
147 let tcx
= checker
.tcx
;
148 let impl_did
= checker
.impl_def_id
;
149 debug
!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did
);
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
154 let span
= tcx
.def_span(impl_did
);
155 tcx
.at(span
).ensure().coerce_unsized_info(impl_did
)
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();
162 debug
!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did
);
164 let span
= tcx
.def_span(impl_did
);
166 let dispatch_from_dyn_trait
= tcx
.require_lang_item(LangItem
::DispatchFromDyn
, Some(span
));
168 let source
= trait_ref
.self_ty();
169 assert
!(!source
.has_escaping_bound_vars());
171 assert_eq
!(trait_ref
.def_id
, dispatch_from_dyn_trait
);
173 trait_ref
.args
.type_at(1)
176 debug
!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source
, target
);
178 let param_env
= tcx
.param_env(impl_did
);
180 let infcx
= tcx
.infer_ctxt().build();
181 let cause
= ObligationCause
::misc(span
, impl_did
);
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.
191 use rustc_type_ir
::TyKind
::*;
192 match (source
.kind(), target
.kind()) {
193 (&Ref(r_a
, _
, mutbl_a
), Ref(r_b
, _
, mutbl_b
)) if r_a
== *r_b
&& mutbl_a
== *mutbl_b
=> {
196 (&RawPtr(_
, a_mutbl
), &RawPtr(_
, b_mutbl
)) if a_mutbl
== b_mutbl
=> Ok(()),
197 (&Adt(def_a
, args_a
), &Adt(def_b
, args_b
)) if def_a
.is_struct() && def_b
.is_struct() => {
199 let source_path
= tcx
.def_path_str(def_a
.did());
200 let target_path
= tcx
.def_path_str(def_b
.did());
202 return Err(tcx
.dcx().emit_err(errors
::DispatchFromDynCoercion
{
204 trait_name
: "DispatchFromDyn",
211 let mut res
= Ok(());
212 if def_a
.repr().c() || def_a
.repr().packed() {
213 res
= Err(tcx
.dcx().emit_err(errors
::DispatchFromDynRepr { span }
));
216 let fields
= &def_a
.non_enum_variant().fields
;
218 let coerced_fields
= fields
221 let ty_a
= field
.ty(tcx
, args_a
);
222 let ty_b
= field
.ty(tcx
, args_b
);
224 if let Ok(layout
) = tcx
.layout_of(param_env
.and(ty_a
)) {
225 if layout
.is_1zst() {
226 // ignore 1-ZST fields
232 res
= Err(tcx
.dcx().emit_err(errors
::DispatchFromDynZST
{
243 .collect
::<Vec
<_
>>();
245 if coerced_fields
.is_empty() {
246 res
= Err(tcx
.dcx().emit_err(errors
::DispatchFromDynSingle
{
248 trait_name
: "DispatchFromDyn",
251 } else if coerced_fields
.len() > 1 {
252 res
= Err(tcx
.dcx().emit_err(errors
::DispatchFromDynMulti
{
254 coercions_note
: true,
255 number
: coerced_fields
.len(),
256 coercions
: coerced_fields
260 "`{}` (`{}` to `{}`)",
262 field
.ty(tcx
, args_a
),
263 field
.ty(tcx
, args_b
),
270 let ocx
= ObligationCtxt
::new_with_diagnostics(&infcx
);
271 for field
in coerced_fields
{
272 ocx
.register_obligation(Obligation
::new(
278 dispatch_from_dyn_trait
,
279 [field
.ty(tcx
, args_a
), field
.ty(tcx
, args_b
)],
283 let errors
= ocx
.select_all_or_error();
284 if !errors
.is_empty() {
285 res
= Err(infcx
.err_ctxt().report_fulfillment_errors(errors
));
288 // Finally, resolve all regions.
289 let outlives_env
= OutlivesEnvironment
::new(param_env
);
290 res
= res
.and(ocx
.resolve_regions_and_report_errors(impl_did
, &outlives_env
));
296 .emit_err(errors
::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" }
)),
300 pub fn coerce_unsized_info
<'tcx
>(
302 impl_did
: LocalDefId
,
303 ) -> Result
<CoerceUnsizedInfo
, ErrorGuaranteed
> {
304 debug
!("compute_coerce_unsized_info(impl_did={:?})", impl_did
);
305 let span
= tcx
.def_span(impl_did
);
307 let coerce_unsized_trait
= tcx
.require_lang_item(LangItem
::CoerceUnsized
, Some(span
));
309 let unsize_trait
= tcx
.require_lang_item(LangItem
::Unsize
, Some(span
));
311 let source
= tcx
.type_of(impl_did
).instantiate_identity();
312 let trait_ref
= tcx
.impl_trait_ref(impl_did
).unwrap().instantiate_identity();
313 assert_eq
!(trait_ref
.def_id
, coerce_unsized_trait
);
314 let target
= trait_ref
.args
.type_at(1);
315 debug
!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source
, target
);
317 let param_env
= tcx
.param_env(impl_did
);
318 assert
!(!source
.has_escaping_bound_vars());
320 debug
!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source
, target
);
322 let infcx
= tcx
.infer_ctxt().build();
323 let cause
= ObligationCause
::misc(span
, impl_did
);
324 let check_mutbl
= |mt_a
: ty
::TypeAndMut
<'tcx
>,
325 mt_b
: ty
::TypeAndMut
<'tcx
>,
326 mk_ptr
: &dyn Fn(Ty
<'tcx
>) -> Ty
<'tcx
>| {
327 if mt_a
.mutbl
< mt_b
.mutbl
{
330 .report_mismatched_types(
334 ty
::error
::TypeError
::Mutability
,
338 (mt_a
.ty
, mt_b
.ty
, unsize_trait
, None
)
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 }
;
345 check_mutbl(mt_a
, mt_b
, &|ty
| Ty
::new_imm_ref(tcx
, r_b
, ty
))
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
),
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
),
360 (&ty
::Adt(def_a
, args_a
), &ty
::Adt(def_b
, args_b
))
361 if def_a
.is_struct() && def_b
.is_struct() =>
364 let source_path
= tcx
.def_path_str(def_a
.did());
365 let target_path
= tcx
.def_path_str(def_b
.did());
366 return Err(tcx
.dcx().emit_err(errors
::DispatchFromDynSame
{
368 trait_name
: "CoerceUnsized",
375 // Here we are considering a case of converting
376 // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
377 // which acts like a pointer to `U`, but carries along some extra data of type `T`:
379 // struct Foo<T, U> {
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:
387 // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
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
393 // extra data `3`). **The purpose of this check is to
394 // make sure that we know how to do this conversion.**
396 // To check if this impl is legal, we would walk down
397 // the fields of `Foo` and consider their types with
398 // both generic parameters. We are looking to find that
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:
405 // - `extra` has type `T` before and type `T` after
406 // - `ptr` has type `*mut U` before and type `*mut V` after
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
417 .filter_map(|(i
, f
)| {
418 let (a
, b
) = (f
.ty(tcx
, args_a
), f
.ty(tcx
, args_b
));
420 if tcx
.type_of(f
.did
).instantiate_identity().is_phantom_data() {
421 // Ignore PhantomData fields
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
430 // variance or constraining opaque types' hidden types.
431 // (This is because we may have to evaluate constraint
432 // expressions in the course of execution.)
438 // Collect up all fields that were significantly changed
439 // i.e., those that contain T in coerce_unsized T -> U
442 .collect
::<Vec
<_
>>();
444 if diff_fields
.is_empty() {
445 return Err(tcx
.dcx().emit_err(errors
::CoerceUnsizedOneField
{
447 trait_name
: "CoerceUnsized",
450 } else if diff_fields
.len() > 1 {
451 let item
= tcx
.hir().expect_item(impl_did
);
452 let span
= if let ItemKind
::Impl(hir
::Impl { of_trait: Some(t), .. }
) = &item
.kind
{
455 tcx
.def_span(impl_did
)
458 return Err(tcx
.dcx().emit_err(errors
::CoerceUnsizedMulti
{
460 coercions_note
: true,
461 number
: diff_fields
.len(),
462 coercions
: diff_fields
464 .map(|&(i
, a
, b
)| format
!("`{}` (`{}` to `{}`)", fields
[i
].name
, a
, b
))
470 let (i
, a
, b
) = diff_fields
[0];
471 let kind
= ty
::adjustment
::CustomCoerceUnsized
::Struct(i
);
472 (a
, b
, coerce_unsized_trait
, Some(kind
))
478 .emit_err(errors
::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }
));
482 // Register an obligation for `A: Trait<B>`.
483 let ocx
= ObligationCtxt
::new_with_diagnostics(&infcx
);
484 let cause
= traits
::ObligationCause
::misc(span
, impl_did
);
485 let obligation
= Obligation
::new(
489 ty
::TraitRef
::new(tcx
, trait_def_id
, [source
, target
]),
491 ocx
.register_obligation(obligation
);
492 let errors
= ocx
.select_all_or_error();
493 if !errors
.is_empty() {
494 infcx
.err_ctxt().report_fulfillment_errors(errors
);
497 // Finally, resolve all regions.
498 let outlives_env
= OutlivesEnvironment
::new(param_env
);
499 let _
= ocx
.resolve_regions_and_report_errors(impl_did
, &outlives_env
);
501 Ok(CoerceUnsizedInfo { custom_kind: kind }
)
504 fn infringing_fields_error(
506 fields
: Vec
<(&ty
::FieldDef
, Ty
<'_
>, InfringingFieldsReason
<'_
>)>,
508 impl_did
: LocalDefId
,
510 ) -> ErrorGuaranteed
{
511 let trait_did
= tcx
.require_lang_item(lang_item
, Some(impl_span
));
513 let trait_name
= tcx
.def_path_str(trait_did
);
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
![];
520 let mut seen_tys
= FxHashSet
::default();
522 let mut label_spans
= Vec
::new();
524 for (field
, ty
, reason
) in fields
{
525 // Only report an error once per type.
526 if !seen_tys
.insert(ty
) {
530 label_spans
.push(tcx
.def_span(field
.did
));
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).
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
{
543 .entry((ty
.to_string(), error_predicate
.to_string()))
545 .push(error
.obligation
.cause
.span
);
547 if let ty
::PredicateKind
::Clause(ty
::ClauseKind
::Trait(ty
::TraitPredicate
{
549 polarity
: ty
::PredicatePolarity
::Positive
,
551 })) = error_predicate
.kind().skip_binder()
553 let ty
= trait_ref
.self_ty();
554 if let ty
::Param(_
) = ty
.kind() {
557 trait_ref
.print_trait_sugared().to_string(),
558 Some(trait_ref
.def_id
),
564 InfringingFieldsReason
::Regions(region_errors
) => {
565 for error
in region_errors
{
566 let ty
= ty
.to_string();
568 RegionResolutionError
::ConcreteFailure(origin
, a
, b
) => {
569 let predicate
= format
!("{b}: {a}");
571 .entry((ty
.clone(), predicate
.clone()))
573 .push(origin
.span());
574 if let ty
::RegionKind
::ReEarlyParam(ebr
) = *b
577 bounds
.push((b
.to_string(), a
.to_string(), None
));
580 RegionResolutionError
::GenericBoundFailure(origin
, a
, b
) => {
581 let predicate
= format
!("{a}: {b}");
583 .entry((ty
.clone(), predicate
.clone()))
585 .push(origin
.span());
586 if let infer
::region_constraints
::GenericKind
::Param(_
) = a
{
587 bounds
.push((a
.to_string(), b
.to_string(), None
));
596 let mut notes
= Vec
::new();
597 for ((ty
, error_predicate
), spans
) in errors
{
598 let span
: MultiSpan
= spans
.into();
599 notes
.push(errors
::ImplForTyRequires
{
602 trait_name
: trait_name
.clone(),
607 let mut err
= tcx
.dcx().create_err(errors
::TraitCannotImplForTy
{
614 suggest_constraining_type_params(
616 tcx
.hir().get_generics(impl_did
).expect("impls always have generics"),
620 .map(|(param
, constraint
, def_id
)| (param
.as_str(), constraint
.as_str(), *def_id
)),