6
6
7
7
use crate :: infer:: outlives:: env:: OutlivesEnvironment ;
8
8
use crate :: infer:: InferOk ;
9
+ use crate :: solve:: inspect;
10
+ use crate :: solve:: inspect:: { InspectGoal , ProofTreeInferCtxtExt , ProofTreeVisitor } ;
11
+ use crate :: traits:: engine:: TraitEngineExt ;
9
12
use crate :: traits:: outlives_bounds:: InferCtxtExt as _;
13
+ use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
10
14
use crate :: traits:: select:: { IntercrateAmbiguityCause , TreatInductiveCycleAs } ;
15
+ use crate :: traits:: structural_normalize:: StructurallyNormalizeExt ;
11
16
use crate :: traits:: util:: impl_subject_and_oblig;
17
+ use crate :: traits:: NormalizeExt ;
12
18
use crate :: traits:: SkipLeakCheck ;
13
19
use crate :: traits:: {
14
20
self , Obligation , ObligationCause , ObligationCtxt , PredicateObligation , PredicateObligations ,
@@ -18,10 +24,13 @@ use rustc_data_structures::fx::FxIndexSet;
18
24
use rustc_errors:: Diagnostic ;
19
25
use rustc_hir:: def_id:: { DefId , CRATE_DEF_ID , LOCAL_CRATE } ;
20
26
use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , TyCtxtInferExt } ;
21
- use rustc_infer:: traits:: util;
27
+ use rustc_infer:: traits:: { util, TraitEngine } ;
28
+ use rustc_middle:: traits:: query:: NoSolution ;
29
+ use rustc_middle:: traits:: solve:: { Certainty , Goal } ;
22
30
use rustc_middle:: traits:: specialization_graph:: OverlapMode ;
23
31
use rustc_middle:: traits:: DefiningAnchor ;
24
32
use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
33
+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
25
34
use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
26
35
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
27
36
use rustc_session:: lint:: builtin:: COINDUCTIVE_OVERLAP_IN_COHERENCE ;
@@ -31,9 +40,6 @@ use std::fmt::Debug;
31
40
use std:: iter;
32
41
use std:: ops:: ControlFlow ;
33
42
34
- use super :: query:: evaluate_obligation:: InferCtxtExt ;
35
- use super :: NormalizeExt ;
36
-
37
43
/// Whether we do the orphan check relative to this crate or
38
44
/// to some remote crate.
39
45
#[ derive( Copy , Clone , Debug ) ]
@@ -289,7 +295,7 @@ fn overlap<'tcx>(
289
295
}
290
296
291
297
let intercrate_ambiguity_causes = if infcx. next_trait_solver ( ) {
292
- crate :: solve :: compute_intercrate_ambiguity_causes ( & infcx, & obligations)
298
+ compute_intercrate_ambiguity_causes ( & infcx, & obligations)
293
299
} else {
294
300
selcx. take_intercrate_ambiguity_causes ( )
295
301
} ;
@@ -884,3 +890,135 @@ where
884
890
ControlFlow :: Continue ( ( ) )
885
891
}
886
892
}
893
+
894
+ /// Compute the `intercrate_ambiguity_causes` for the new solver using
895
+ /// "proof trees".
896
+ fn compute_intercrate_ambiguity_causes < ' tcx > (
897
+ infcx : & InferCtxt < ' tcx > ,
898
+ obligations : & [ PredicateObligation < ' tcx > ] ,
899
+ ) -> FxIndexSet < IntercrateAmbiguityCause > {
900
+ let mut causes: FxIndexSet < IntercrateAmbiguityCause > = Default :: default ( ) ;
901
+
902
+ for obligation in obligations {
903
+ search_ambiguity_causes ( infcx, obligation. clone ( ) . into ( ) , & mut causes) ;
904
+ }
905
+
906
+ causes
907
+ }
908
+
909
+ struct AmbiguityCausesVisitor < ' a > {
910
+ causes : & ' a mut FxIndexSet < IntercrateAmbiguityCause > ,
911
+ }
912
+
913
+ impl < ' a , ' tcx > ProofTreeVisitor < ' tcx > for AmbiguityCausesVisitor < ' a > {
914
+ type BreakTy = !;
915
+ fn visit_goal ( & mut self , goal : & InspectGoal < ' _ , ' tcx > ) -> ControlFlow < Self :: BreakTy > {
916
+ let infcx = goal. infcx ( ) ;
917
+ for cand in goal. candidates ( ) {
918
+ cand. visit_nested ( self ) ?;
919
+ }
920
+ // When searching for intercrate ambiguity causes, we only need to look
921
+ // at ambiguous goals, as for others the coherence unknowable candidate
922
+ // was irrelevant.
923
+ match goal. result ( ) {
924
+ Ok ( Certainty :: Maybe ( _) ) => { }
925
+ Ok ( Certainty :: Yes ) | Err ( NoSolution ) => return ControlFlow :: Continue ( ( ) ) ,
926
+ }
927
+
928
+ let Goal { param_env, predicate } = goal. goal ( ) ;
929
+
930
+ let trait_ref = match predicate. kind ( ) . no_bound_vars ( ) {
931
+ Some ( ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( tr) ) ) => tr. trait_ref ,
932
+ Some ( ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( proj) ) ) => {
933
+ proj. projection_ty . trait_ref ( infcx. tcx )
934
+ }
935
+ _ => return ControlFlow :: Continue ( ( ) ) ,
936
+ } ;
937
+
938
+ let mut ambiguity_cause = None ;
939
+ for cand in goal. candidates ( ) {
940
+ match cand. result ( ) {
941
+ Ok ( Certainty :: Maybe ( _) ) => { }
942
+ // We only add intercrate ambiguity causes if the goal would
943
+ // otherwise result in an error.
944
+ //
945
+ // FIXME: this isn't quite right. Changing a goal from YES with
946
+ // inference contraints to AMBIGUOUS can also cause a goal to not
947
+ // fail.
948
+ Ok ( Certainty :: Yes ) => {
949
+ ambiguity_cause = None ;
950
+ break ;
951
+ }
952
+ Err ( NoSolution ) => continue ,
953
+ }
954
+
955
+ // FIXME: boiiii, using string comparisions here sure is scuffed.
956
+ if let inspect:: ProbeKind :: MiscCandidate { name : "coherence unknowable" , result : _ } =
957
+ cand. kind ( )
958
+ {
959
+ let lazily_normalize_ty = |ty : Ty < ' tcx > | {
960
+ let mut fulfill_cx = <dyn TraitEngine < ' tcx > >:: new ( infcx) ;
961
+ if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
962
+ match infcx
963
+ . at ( & ObligationCause :: dummy ( ) , param_env)
964
+ . structurally_normalize ( ty, & mut * fulfill_cx)
965
+ {
966
+ Ok ( ty) => Ok ( ty) ,
967
+ Err ( _errs) => Err ( ( ) ) ,
968
+ }
969
+ } else {
970
+ Ok ( ty)
971
+ }
972
+ } ;
973
+
974
+ infcx. probe ( |_| {
975
+ match trait_ref_is_knowable ( infcx. tcx , trait_ref, lazily_normalize_ty) {
976
+ Err ( ( ) ) => { }
977
+ Ok ( Ok ( ( ) ) ) => warn ! ( "expected an unknowable trait ref: {trait_ref:?}" ) ,
978
+ Ok ( Err ( conflict) ) => {
979
+ let trait_ref = infcx. resolve_vars_if_possible ( trait_ref) ;
980
+ if !trait_ref. references_error ( ) {
981
+ let self_ty = trait_ref. self_ty ( ) ;
982
+ let ( trait_desc, self_desc) = with_no_trimmed_paths ! ( {
983
+ let trait_desc = trait_ref. print_only_trait_path( ) . to_string( ) ;
984
+ let self_desc = self_ty
985
+ . has_concrete_skeleton( )
986
+ . then( || self_ty. to_string( ) ) ;
987
+ ( trait_desc, self_desc)
988
+ } ) ;
989
+ ambiguity_cause = Some ( match conflict {
990
+ Conflict :: Upstream => {
991
+ IntercrateAmbiguityCause :: UpstreamCrateUpdate {
992
+ trait_desc,
993
+ self_desc,
994
+ }
995
+ }
996
+ Conflict :: Downstream => {
997
+ IntercrateAmbiguityCause :: DownstreamCrate {
998
+ trait_desc,
999
+ self_desc,
1000
+ }
1001
+ }
1002
+ } ) ;
1003
+ }
1004
+ }
1005
+ }
1006
+ } )
1007
+ }
1008
+ }
1009
+
1010
+ if let Some ( ambiguity_cause) = ambiguity_cause {
1011
+ self . causes . insert ( ambiguity_cause) ;
1012
+ }
1013
+
1014
+ ControlFlow :: Continue ( ( ) )
1015
+ }
1016
+ }
1017
+
1018
+ fn search_ambiguity_causes < ' tcx > (
1019
+ infcx : & InferCtxt < ' tcx > ,
1020
+ goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ,
1021
+ causes : & mut FxIndexSet < IntercrateAmbiguityCause > ,
1022
+ ) {
1023
+ infcx. visit_proof_tree ( goal, & mut AmbiguityCausesVisitor { causes } ) ;
1024
+ }
0 commit comments