@@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
1616use rustc_infer:: infer:: canonical:: CanonicalVarValues ;
1717use rustc_infer:: infer:: canonical:: { CanonicalExt , QueryRegionConstraints } ;
1818use rustc_middle:: traits:: query:: NoSolution ;
19- use rustc_middle:: traits:: solve:: { ExternalConstraints , ExternalConstraintsData } ;
19+ use rustc_middle:: traits:: solve:: { ExternalConstraints , ExternalConstraintsData , MaybeCause } ;
2020use rustc_middle:: ty:: { self , BoundVar , GenericArgKind } ;
2121use rustc_span:: DUMMY_SP ;
2222use std:: iter;
@@ -60,9 +60,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
6060
6161 let certainty = certainty. unify_with ( goals_certainty) ;
6262
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+ } ;
6483
65- let response = Response { var_values : self . var_values , external_constraints, certainty } ;
6684 let canonical = Canonicalizer :: canonicalize (
6785 self . infcx ,
6886 CanonicalizeMode :: Response { max_input_universe : self . max_input_universe } ,
@@ -72,6 +90,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
7290 Ok ( canonical)
7391 }
7492
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+
75127 #[ instrument( level = "debug" , skip( self ) , ret) ]
76128 fn compute_external_query_constraints ( & self ) -> Result < ExternalConstraints < ' tcx > , NoSolution > {
77129 // Cannot use `take_registered_region_obligations` as we may compute the response
0 commit comments