Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::LocalDefId;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt};
use rustc_span::Span;

use crate::infer::canonical::{
Expand All @@ -25,6 +25,31 @@ pub use rustc_middle::traits::query::type_op::*;

use self::custom::scrape_region_constraints;

/// Replaces the param env of a type op goal with the empty one when it cannot affect the
/// outcome.
///
/// The canonicalized goal is a query cache key, so an irrelevant param env still keeps
/// bodies with unrelated where-clauses from sharing an entry. A caller bound mentioning a
/// generic parameter can never apply to a goal which mentions only global names, and
/// outlives clauses are not assembled as candidates for trait or projection goals.
fn erase_irrelevant_param_env<'tcx, Q: TypeVisitable<TyCtxt<'tcx>>>(
query_key: ParamEnvAnd<'tcx, Q>,
) -> ParamEnvAnd<'tcx, Q> {
if query_key.value.is_global()
&& query_key.param_env.caller_bounds().iter().all(|bound| {
bound.has_param()
|| matches!(
bound.kind().skip_binder(),
ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::TypeOutlives(_)
)
})
{
ParamEnvAnd { param_env: ty::ParamEnv::empty(), value: query_key.value }
} else {
query_key
}
}

/// "Type ops" are used in NLL to perform some particular action and
/// extract out the resulting region constraints (or an error if it
/// cannot be completed).
Expand Down Expand Up @@ -118,7 +143,8 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't

let mut canonical_var_values = OriginalQueryValues::default();
let old_param_env = query_key.param_env;
let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values);
let canonical_self = infcx
.canonicalize_query(erase_irrelevant_param_env(query_key), &mut canonical_var_values);
let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;

let InferOk { value, obligations } = infcx
Expand Down
Loading