Rollup merge of #90023 - b-naber:postpone_const_eval_infer_vars, r=nikomatsakis

Postpone the evaluation of constant expressions that depend on inference variables

Previously `delay_span_bug` calls were triggered once an inference variable was included in the substs of a constant that was to be evaluated. Some of these would merely have resulted in trait candidates being rejected, hence no real error was ever encountered, but the triggering of the `delay_span_bug` then caused an ICE in later stages of the compiler due to no error ever occurring.
We now postpone the evaluation of these constants, so any trait obligation fulfillment will simply stall on this constant and the existing type inference machinery of the compiler handles any type errors if present.

Fixes https://github.com/rust-lang/rust/issues/89320
Fixes https://github.com/rust-lang/rust/issues/89146
Fixes https://github.com/rust-lang/rust/issues/87964
Fixes https://github.com/rust-lang/rust/issues/87470
Fixes https://github.com/rust-lang/rust/issues/83288
Fixes https://github.com/rust-lang/rust/issues/83249
Fixes https://github.com/rust-lang/rust/issues/90654

I want to thank `@BoxyUwU` for cooperating on this and for providing some help.

r? `@lcnr` maybe?
This commit is contained in:
Matthias Krüger
2021-12-05 00:37:58 +01:00
committed by GitHub
11 changed files with 325 additions and 34 deletions

View File

@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -1584,13 +1585,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
let mut original_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
let mut substs = unevaluated.substs(self.tcx);
substs = self.resolve_vars_if_possible(substs);
// Postpone the evaluation of constants whose substs depend on inference
// variables
if substs.has_infer_types_or_consts() {
return Err(ErrorHandled::TooGeneric);
}
let param_env_erased = self.tcx.erase_regions(param_env);
let substs_erased = self.tcx.erase_regions(substs);
let unevaluated = ty::Unevaluated {
def: unevaluated.def,
substs_: Some(substs_erased),
promoted: unevaluated.promoted,
};
let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
self.tcx.const_eval_resolve(param_env, unevaluated, span)
self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
}
/// If `typ` is a type variable of some kind, resolve it one level