@@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
16
16
use rustc_infer:: infer:: canonical:: CanonicalVarValues ;
17
17
use rustc_infer:: infer:: canonical:: { CanonicalExt , QueryRegionConstraints } ;
18
18
use rustc_middle:: traits:: query:: NoSolution ;
19
- use rustc_middle:: traits:: solve:: { ExternalConstraints , ExternalConstraintsData } ;
19
+ use rustc_middle:: traits:: solve:: { ExternalConstraints , ExternalConstraintsData , MaybeCause } ;
20
20
use rustc_middle:: ty:: { self , BoundVar , GenericArgKind } ;
21
21
use rustc_span:: DUMMY_SP ;
22
22
use std:: iter;
@@ -60,9 +60,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
60
60
61
61
let certainty = certainty. unify_with ( goals_certainty) ;
62
62
63
- let external_constraints = self . compute_external_query_constraints ( ) ?;
63
+ let response = match certainty {
64
+ Certainty :: Yes | Certainty :: Maybe ( MaybeCause :: Ambiguity ) => {
65
+ let external_constraints = self . compute_external_query_constraints ( ) ?;
66
+ Response { var_values : self . var_values , external_constraints, certainty }
67
+ }
68
+ Certainty :: Maybe ( MaybeCause :: Overflow ) => {
69
+ // If we have overflow, it's probable that we're substituting a type
70
+ // into itself infinitely and any partial substitutions in the query
71
+ // response are probably not useful anyways, so just return an empty
72
+ // query response.
73
+ //
74
+ // This may prevent us from potentially useful inference, e.g.
75
+ // 2 candidates, one ambiguous and one overflow, which both
76
+ // have the same inference constraints.
77
+ //
78
+ // Changing this to retain some constraints in the future
79
+ // won't be a breaking change, so this is good enough for now.
80
+ return Ok ( self . make_ambiguous_response_no_constraints ( MaybeCause :: Overflow ) ) ;
81
+ }
82
+ } ;
64
83
65
- let response = Response { var_values : self . var_values , external_constraints, certainty } ;
66
84
let canonical = Canonicalizer :: canonicalize (
67
85
self . infcx ,
68
86
CanonicalizeMode :: Response { max_input_universe : self . max_input_universe } ,
@@ -72,6 +90,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
72
90
Ok ( canonical)
73
91
}
74
92
93
+ /// Constructs a totally unconstrained, ambiguous response to a goal.
94
+ ///
95
+ /// Take care when using this, since often it's useful to respond with
96
+ /// ambiguity but return constrained variables to guide inference.
97
+ pub ( in crate :: solve) fn make_ambiguous_response_no_constraints (
98
+ & self ,
99
+ maybe_cause : MaybeCause ,
100
+ ) -> CanonicalResponse < ' tcx > {
101
+ let unconstrained_response = Response {
102
+ var_values : CanonicalVarValues {
103
+ var_values : self . tcx ( ) . mk_substs_from_iter ( self . var_values . var_values . iter ( ) . map (
104
+ |arg| -> ty:: GenericArg < ' tcx > {
105
+ match arg. unpack ( ) {
106
+ GenericArgKind :: Lifetime ( _) => self . next_region_infer ( ) . into ( ) ,
107
+ GenericArgKind :: Type ( _) => self . next_ty_infer ( ) . into ( ) ,
108
+ GenericArgKind :: Const ( ct) => self . next_const_infer ( ct. ty ( ) ) . into ( ) ,
109
+ }
110
+ } ,
111
+ ) ) ,
112
+ } ,
113
+ external_constraints : self
114
+ . tcx ( )
115
+ . mk_external_constraints ( ExternalConstraintsData :: default ( ) ) ,
116
+ certainty : Certainty :: Maybe ( maybe_cause) ,
117
+ } ;
118
+
119
+ Canonicalizer :: canonicalize (
120
+ self . infcx ,
121
+ CanonicalizeMode :: Response { max_input_universe : self . max_input_universe } ,
122
+ & mut Default :: default ( ) ,
123
+ unconstrained_response,
124
+ )
125
+ }
126
+
75
127
#[ instrument( level = "debug" , skip( self ) , ret) ]
76
128
fn compute_external_query_constraints ( & self ) -> Result < ExternalConstraints < ' tcx > , NoSolution > {
77
129
// Cannot use `take_registered_region_obligations` as we may compute the response
0 commit comments