@@ -51,11 +51,8 @@ use std::path::PathBuf;
5151use std:: { cmp, fmt, iter} ;
5252
5353use rustc_abi:: ExternAbi ;
54- use rustc_ast:: join_path_syms;
5554use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
56- use rustc_errors:: {
57- Applicability , Diag , DiagStyledString , IntoDiagArg , MultiSpan , StringPart , pluralize,
58- } ;
55+ use rustc_errors:: { Applicability , Diag , DiagStyledString , IntoDiagArg , StringPart , pluralize} ;
5956use rustc_hir:: def:: DefKind ;
6057use rustc_hir:: def_id:: DefId ;
6158use rustc_hir:: intravisit:: Visitor ;
@@ -66,15 +63,12 @@ use rustc_middle::bug;
6663use rustc_middle:: dep_graph:: DepContext ;
6764use rustc_middle:: traits:: PatternOriginExpr ;
6865use rustc_middle:: ty:: error:: { ExpectedFound , TypeError , TypeErrorToStringExt } ;
69- use rustc_middle:: ty:: print:: {
70- PrintError , PrintTraitRefExt as _, WrapBinderMode , with_forced_trimmed_paths,
71- } ;
66+ use rustc_middle:: ty:: print:: { PrintTraitRefExt as _, WrapBinderMode , with_forced_trimmed_paths} ;
7267use rustc_middle:: ty:: {
7368 self , List , ParamEnv , Region , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
7469 TypeVisitableExt ,
7570} ;
76- use rustc_span:: def_id:: LOCAL_CRATE ;
77- use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Pos , Span , Symbol , sym} ;
71+ use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Pos , Span , sym} ;
7872use tracing:: { debug, instrument} ;
7973
8074use crate :: error_reporting:: TypeErrCtxt ;
@@ -216,213 +210,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
216210
217211 /// Adds a note if the types come from similarly named crates
218212 fn check_and_note_conflicting_crates ( & self , err : & mut Diag < ' _ > , terr : TypeError < ' tcx > ) -> bool {
219- // FIXME(estebank): unify with `report_similar_impl_candidates`. The message is similar,
220- // even if the logic needed to detect the case is very different.
221- use hir:: def_id:: CrateNum ;
222- use rustc_hir:: definitions:: DisambiguatedDefPathData ;
223- use ty:: GenericArg ;
224- use ty:: print:: Printer ;
225-
226- struct ConflictingPathPrinter < ' tcx > {
227- tcx : TyCtxt < ' tcx > ,
228- segments : Vec < Symbol > ,
229- }
230-
231- impl < ' tcx > Printer < ' tcx > for ConflictingPathPrinter < ' tcx > {
232- fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' tcx > {
233- self . tcx
234- }
235-
236- fn print_region ( & mut self , _region : ty:: Region < ' _ > ) -> Result < ( ) , PrintError > {
237- unreachable ! ( ) ; // because `print_path_with_generic_args` ignores the `GenericArgs`
238- }
239-
240- fn print_type ( & mut self , _ty : Ty < ' tcx > ) -> Result < ( ) , PrintError > {
241- unreachable ! ( ) ; // because `print_path_with_generic_args` ignores the `GenericArgs`
242- }
243-
244- fn print_dyn_existential (
245- & mut self ,
246- _predicates : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
247- ) -> Result < ( ) , PrintError > {
248- unreachable ! ( ) ; // because `print_path_with_generic_args` ignores the `GenericArgs`
249- }
250-
251- fn print_const ( & mut self , _ct : ty:: Const < ' tcx > ) -> Result < ( ) , PrintError > {
252- unreachable ! ( ) ; // because `print_path_with_generic_args` ignores the `GenericArgs`
253- }
254-
255- fn print_crate_name ( & mut self , cnum : CrateNum ) -> Result < ( ) , PrintError > {
256- self . segments = vec ! [ self . tcx. crate_name( cnum) ] ;
257- Ok ( ( ) )
258- }
259-
260- fn print_path_with_qualified (
261- & mut self ,
262- _self_ty : Ty < ' tcx > ,
263- _trait_ref : Option < ty:: TraitRef < ' tcx > > ,
264- ) -> Result < ( ) , PrintError > {
265- Err ( fmt:: Error )
266- }
267-
268- fn print_path_with_impl (
269- & mut self ,
270- _print_prefix : impl FnOnce ( & mut Self ) -> Result < ( ) , PrintError > ,
271- _self_ty : Ty < ' tcx > ,
272- _trait_ref : Option < ty:: TraitRef < ' tcx > > ,
273- ) -> Result < ( ) , PrintError > {
274- Err ( fmt:: Error )
275- }
276-
277- fn print_path_with_simple (
278- & mut self ,
279- print_prefix : impl FnOnce ( & mut Self ) -> Result < ( ) , PrintError > ,
280- disambiguated_data : & DisambiguatedDefPathData ,
281- ) -> Result < ( ) , PrintError > {
282- print_prefix ( self ) ?;
283- self . segments . push ( disambiguated_data. as_sym ( true ) ) ;
284- Ok ( ( ) )
285- }
286-
287- fn print_path_with_generic_args (
288- & mut self ,
289- print_prefix : impl FnOnce ( & mut Self ) -> Result < ( ) , PrintError > ,
290- _args : & [ GenericArg < ' tcx > ] ,
291- ) -> Result < ( ) , PrintError > {
292- print_prefix ( self )
293- }
294- }
295-
296- let report_path_match = |err : & mut Diag < ' _ > , did1 : DefId , did2 : DefId , ty : & str | -> bool {
297- // Only report definitions from different crates. If both definitions
298- // are from a local module we could have false positives, e.g.
299- // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
300- if did1. krate != did2. krate {
301- let abs_path = |def_id| {
302- let mut p = ConflictingPathPrinter { tcx : self . tcx , segments : vec ! [ ] } ;
303- p. print_def_path ( def_id, & [ ] ) . map ( |_| p. segments )
304- } ;
305-
306- // We compare strings because DefPath can be different for imported and
307- // non-imported crates.
308- let expected_str = self . tcx . def_path_str ( did1) ;
309- let found_str = self . tcx . def_path_str ( did2) ;
310- let Ok ( expected_abs) = abs_path ( did1) else { return false } ;
311- let Ok ( found_abs) = abs_path ( did2) else { return false } ;
312- let same_path = expected_str == found_str || expected_abs == found_abs;
313- if same_path {
314- // We want to use as unique a type path as possible. If both types are "locally
315- // known" by the same name, we use the "absolute path" which uses the original
316- // crate name instead.
317- let ( expected, found) = if expected_str == found_str {
318- ( join_path_syms ( & expected_abs) , join_path_syms ( & found_abs) )
319- } else {
320- ( expected_str, found_str)
321- } ;
322-
323- // We've displayed "expected `a::b`, found `a::b`". We add context to
324- // differentiate the different cases where that might happen.
325- let expected_crate_name = self . tcx . crate_name ( did1. krate ) ;
326- let found_crate_name = self . tcx . crate_name ( did2. krate ) ;
327- let same_crate = expected_crate_name == found_crate_name;
328- let expected_sp = self . tcx . def_span ( did1) ;
329- let found_sp = self . tcx . def_span ( did2) ;
330-
331- let both_direct_dependencies = if !did1. is_local ( )
332- && !did2. is_local ( )
333- && let Some ( data1) = self . tcx . extern_crate ( did1. krate )
334- && let Some ( data2) = self . tcx . extern_crate ( did2. krate )
335- && data1. dependency_of == LOCAL_CRATE
336- && data2. dependency_of == LOCAL_CRATE
337- {
338- // If both crates are directly depended on, we don't want to mention that
339- // in the final message, as it is redundant wording.
340- // We skip the case of semver trick, where one version of the local crate
341- // depends on another version of itself by checking that both crates at play
342- // are not the current one.
343- true
344- } else {
345- false
346- } ;
347-
348- let mut span: MultiSpan = vec ! [ expected_sp, found_sp] . into ( ) ;
349- span. push_span_label (
350- self . tcx . def_span ( did1) ,
351- format ! ( "this is the expected {ty} `{expected}`" ) ,
352- ) ;
353- span. push_span_label (
354- self . tcx . def_span ( did2) ,
355- format ! ( "this is the found {ty} `{found}`" ) ,
356- ) ;
357- for def_id in [ did1, did2] {
358- let crate_name = self . tcx . crate_name ( def_id. krate ) ;
359- if !def_id. is_local ( )
360- && let Some ( data) = self . tcx . extern_crate ( def_id. krate )
361- {
362- let descr = if same_crate {
363- "one version of" . to_string ( )
364- } else {
365- format ! ( "one {ty} comes from" )
366- } ;
367- let dependency = if both_direct_dependencies {
368- if let rustc_session:: cstore:: ExternCrateSource :: Extern ( def_id) =
369- data. src
370- && let Some ( name) = self . tcx . opt_item_name ( def_id)
371- {
372- format ! ( ", which is renamed locally to `{name}`" )
373- } else {
374- String :: new ( )
375- }
376- } else if data. dependency_of == LOCAL_CRATE {
377- ", as a direct dependency of the current crate" . to_string ( )
378- } else {
379- let dep = self . tcx . crate_name ( data. dependency_of ) ;
380- format ! ( ", as a dependency of crate `{dep}`" )
381- } ;
382- span. push_span_label (
383- data. span ,
384- format ! ( "{descr} crate `{crate_name}` used here{dependency}" ) ,
385- ) ;
386- }
387- }
388- let msg = if ( did1. is_local ( ) || did2. is_local ( ) ) && same_crate {
389- format ! (
390- "the crate `{expected_crate_name}` is compiled multiple times, \
391- possibly with different configurations",
392- )
393- } else if same_crate {
394- format ! (
395- "two different versions of crate `{expected_crate_name}` are being \
396- used; two types coming from two different versions of the same crate \
397- are different types even if they look the same",
398- )
399- } else {
400- format ! (
401- "two types coming from two different crates are different types even \
402- if they look the same",
403- )
404- } ;
405- err. span_note ( span, msg) ;
406- if same_crate {
407- err. help ( "you can use `cargo tree` to explore your dependency tree" ) ;
408- }
409- return true ;
410- }
411- }
412- false
413- } ;
414213 match terr {
415214 TypeError :: Sorts ( ref exp_found) => {
416215 // if they are both "path types", there's a chance of ambiguity
417216 // due to different versions of the same crate
418217 if let ( & ty:: Adt ( exp_adt, _) , & ty:: Adt ( found_adt, _) ) =
419218 ( exp_found. expected . kind ( ) , exp_found. found . kind ( ) )
420219 {
421- return report_path_match ( err, exp_adt. did ( ) , found_adt. did ( ) , "type" ) ;
220+ return self . check_same_definition_different_crate (
221+ err,
222+ exp_adt. did ( ) ,
223+ [ found_adt. did ( ) ] . into_iter ( ) ,
224+ |did| vec ! [ self . tcx. def_span( did) ] ,
225+ "type" ,
226+ ) ;
422227 }
423228 }
424229 TypeError :: Traits ( ref exp_found) => {
425- return report_path_match ( err, exp_found. expected , exp_found. found , "trait" ) ;
230+ return self . check_same_definition_different_crate (
231+ err,
232+ exp_found. expected ,
233+ [ exp_found. found ] . into_iter ( ) ,
234+ |did| vec ! [ self . tcx. def_span( did) ] ,
235+ "trait" ,
236+ ) ;
426237 }
427238 _ => ( ) , // FIXME(#22750) handle traits and stuff
428239 }
0 commit comments