@@ -106,3 +106,95 @@ fn must_be_clonable(
106
106
. build ( ) ;
107
107
diagnostics. push ( diagnostic. into ( ) ) ;
108
108
}
109
+
110
+ /// Check all types whose cloning strategy is set to "NeverClone" are not Copy.
111
+ #[ tracing:: instrument(
112
+ name = "If cloning is not allowed, types should not be copyable" ,
113
+ skip_all
114
+ ) ]
115
+ pub ( crate ) fn never_clones_should_not_be_copyable < ' a > (
116
+ component_db : & ComponentDb ,
117
+ computation_db : & ComputationDb ,
118
+ package_graph : & PackageGraph ,
119
+ krate_collection : & CrateCollection ,
120
+ diagnostics : & mut Vec < miette:: Error > ,
121
+ ) {
122
+ let copy = process_framework_path ( "core::marker::Copy" , krate_collection) ;
123
+ let ResolvedType :: ResolvedPath ( copy) = copy else {
124
+ unreachable ! ( )
125
+ } ;
126
+
127
+ for ( id, _) in component_db. iter ( ) {
128
+ let HydratedComponent :: Constructor ( constructor) =
129
+ component_db. hydrated_component ( id, computation_db)
130
+ else {
131
+ continue ;
132
+ } ;
133
+ if component_db. cloning_strategy ( id) != CloningStrategy :: NeverClone {
134
+ continue ;
135
+ }
136
+ let output_type = constructor. output_type ( ) ;
137
+ if let Ok ( ( ) ) = assert_trait_is_implemented ( krate_collection, output_type, & copy) {
138
+ should_not_be_never_clone (
139
+ output_type,
140
+ id,
141
+ package_graph,
142
+ component_db,
143
+ computation_db,
144
+ diagnostics,
145
+ ) ;
146
+ }
147
+ }
148
+ }
149
+
150
+ fn should_not_be_never_clone (
151
+ type_ : & ResolvedType ,
152
+ component_id : ComponentId ,
153
+ package_graph : & PackageGraph ,
154
+ component_db : & ComponentDb ,
155
+ computation_db : & ComputationDb ,
156
+ diagnostics : & mut Vec < miette:: Error > ,
157
+ ) {
158
+ let component_id = component_db
159
+ . derived_from ( & component_id)
160
+ . unwrap_or ( component_id) ;
161
+ let user_component_id = component_db. user_component_id ( component_id) . unwrap ( ) ;
162
+ let user_component_db = & component_db. user_component_db ( ) ;
163
+ let callable_type = user_component_db[ user_component_id] . callable_type ( ) ;
164
+ let location = user_component_db. get_location ( user_component_id) ;
165
+ let source = try_source ! ( location, package_graph, diagnostics) ;
166
+ let label = source. as_ref ( ) . and_then ( |source| {
167
+ diagnostic:: get_f_macro_invocation_span ( source, location)
168
+ . labeled ( format ! ( "The {callable_type} was registered here" ) )
169
+ } ) ;
170
+ let warning_msg = match callable_type {
171
+ CallableType :: Constructor => {
172
+ let callable_path = & computation_db[ user_component_id] . path ;
173
+ format ! (
174
+ "A type should not be copyable if you set its cloning strategy to `NeverClone`.\n \
175
+ The cloning strategy for `{callable_path}` is `NeverClone`, but `{}`, its output type, implements the `Copy` trait.",
176
+ type_. display_for_error( ) ,
177
+ )
178
+ }
179
+ CallableType :: PrebuiltType => {
180
+ format ! (
181
+ "A type should not be copyable if you set its cloning strategy to `NeverClone`.\n \
182
+ The cloning strategy for `{}`, a prebuilt type, is `NeverClone`, but it implements the `Copy` trait.",
183
+ type_. display_for_error( ) ,
184
+ )
185
+ }
186
+ _ => unreachable ! ( ) ,
187
+ } ;
188
+ let e = anyhow:: anyhow!( "copyable type is marked NeverClone" ) . context ( warning_msg) ;
189
+ let help = format ! (
190
+ "Either set the cloning strategy to `CloneIfNecessary` or remove `Copy` for `{}`" ,
191
+ type_. display_for_error( )
192
+ ) ;
193
+ let diagnostic = CompilerDiagnostic :: builder ( e)
194
+ . severity ( miette:: Severity :: Warning )
195
+ . optional_source ( source)
196
+ . optional_label ( label)
197
+ . help ( help)
198
+ . build ( ) ;
199
+ diagnostics. push ( diagnostic. into ( ) ) ;
200
+ }
0 commit comments