2
2
//! up data structures required by type-checking/codegen.
3
3
4
4
use crate :: errors:: { CopyImplOnNonAdt , CopyImplOnTypeWithDtor , DropImplOnWrongItem } ;
5
- use rustc_errors:: struct_span_err;
5
+ use rustc_errors:: { struct_span_err, MultiSpan } ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
8
8
use rustc_hir:: lang_items:: LangItem ;
@@ -11,12 +11,12 @@ use rustc_infer::infer;
11
11
use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
12
12
use rustc_infer:: infer:: { RegionckMode , TyCtxtInferExt } ;
13
13
use rustc_middle:: ty:: adjustment:: CoerceUnsizedInfo ;
14
- use rustc_middle:: ty:: TypeFoldable ;
15
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
14
+ use rustc_middle:: ty:: { self , suggest_constraining_type_params, Ty , TyCtxt , TypeFoldable } ;
16
15
use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
17
16
use rustc_trait_selection:: traits:: misc:: { can_type_implement_copy, CopyImplementationError } ;
18
17
use rustc_trait_selection:: traits:: predicate_for_trait_def;
19
18
use rustc_trait_selection:: traits:: { self , ObligationCause , TraitEngine , TraitEngineExt } ;
19
+ use std:: collections:: BTreeMap ;
20
20
21
21
pub fn check_trait ( tcx : TyCtxt < ' _ > , trait_def_id : DefId ) {
22
22
let lang_items = tcx. lang_items ( ) ;
@@ -91,6 +91,20 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
91
91
E0204 ,
92
92
"the trait `Copy` may not be implemented for this type"
93
93
) ;
94
+
95
+ // We'll try to suggest constraining type parameters to fulfill the requirements of
96
+ // their `Copy` implementation.
97
+ let mut generics = None ;
98
+ if let ty:: Adt ( def, _substs) = self_type. kind ( ) {
99
+ let self_def_id = def. did ( ) ;
100
+ if let Some ( local) = self_def_id. as_local ( ) {
101
+ let self_item = tcx. hir ( ) . expect_item ( local) ;
102
+ generics = self_item. kind . generics ( ) ;
103
+ }
104
+ }
105
+ let mut errors: BTreeMap < _ , Vec < _ > > = Default :: default ( ) ;
106
+ let mut bounds = vec ! [ ] ;
107
+
94
108
for ( field, ty) in fields {
95
109
let field_span = tcx. def_span ( field. did ) ;
96
110
err. span_label ( field_span, "this field does not implement `Copy`" ) ;
@@ -115,17 +129,46 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
115
129
// FIXME: This error could be more descriptive, especially if the error_predicate
116
130
// contains a foreign type or if it's a deeply nested type...
117
131
if error_predicate != error. root_obligation . predicate {
118
- err. span_note (
119
- error. obligation . cause . span ,
120
- & format ! (
121
- "the `Copy` impl for `{}` requires that `{}`" ,
122
- ty, error_predicate
123
- ) ,
124
- ) ;
132
+ errors
133
+ . entry ( ( ty. to_string ( ) , error_predicate. to_string ( ) ) )
134
+ . or_default ( )
135
+ . push ( error. obligation . cause . span ) ;
136
+ }
137
+ if let ty:: PredicateKind :: Trait ( ty:: TraitPredicate {
138
+ trait_ref,
139
+ polarity : ty:: ImplPolarity :: Positive ,
140
+ ..
141
+ } ) = error_predicate. kind ( ) . skip_binder ( )
142
+ {
143
+ let ty = trait_ref. self_ty ( ) ;
144
+ if let ty:: Param ( _) = ty. kind ( ) {
145
+ bounds. push ( (
146
+ format ! ( "{ty}" ) ,
147
+ trait_ref. print_only_trait_path ( ) . to_string ( ) ,
148
+ Some ( trait_ref. def_id ) ,
149
+ ) ) ;
150
+ }
125
151
}
126
152
}
127
153
} ) ;
128
154
}
155
+ for ( ( ty, error_predicate) , spans) in errors {
156
+ let span: MultiSpan = spans. into ( ) ;
157
+ err. span_note (
158
+ span,
159
+ & format ! ( "the `Copy` impl for `{}` requires that `{}`" , ty, error_predicate) ,
160
+ ) ;
161
+ }
162
+ if let Some ( generics) = generics {
163
+ suggest_constraining_type_params (
164
+ tcx,
165
+ generics,
166
+ & mut err,
167
+ bounds. iter ( ) . map ( |( param, constraint, def_id) | {
168
+ ( param. as_str ( ) , constraint. as_str ( ) , * def_id)
169
+ } ) ,
170
+ ) ;
171
+ }
129
172
err. emit ( ) ;
130
173
}
131
174
Err ( CopyImplementationError :: NotAnAdt ) => {
0 commit comments