pub mod auto_trait;
mod chalk_fulfill;
pub mod codegen;
mod coherence;
mod const_evaluatable;
mod engine;
pub mod error_reporting;
mod fulfill;
pub mod misc;
mod object_safety;
mod on_unimplemented;
mod project;
pub mod query;
mod select;
mod specialize;
mod structural_match;
mod util;
pub mod wf;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
};
use rustc_span::Span;
use std::fmt::Debug;
pub use self::FulfillmentErrorCode::*;
pub use self::ImplSource::*;
pub use self::ObligationCauseCode::*;
pub use self::SelectionError::*;
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
pub use self::coherence::{OrphanCheckErr, OverlapResult};
pub use self::engine::TraitEngineExt;
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
pub use self::project::{normalize, normalize_projection_type, normalize_to};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_match::NonStructuralMatchTy;
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
};
pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
pub use rustc_infer::traits::*;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum SkipLeakCheck {
Yes,
No,
}
impl SkipLeakCheck {
fn is_yes(self) -> bool {
self == SkipLeakCheck::Yes
}
}
impl Default for SkipLeakCheck {
fn default() -> Self {
SkipLeakCheck::No
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TraitQueryMode {
Standard,
Canonical,
}
pub fn predicates_for_generics<'tcx>(
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
util::predicates_for_generics(cause, 0, param_env, generic_bounds)
}
pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span,
) -> bool {
debug!(
"type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
ty,
infcx.tcx.def_path_str(def_id)
);
let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
let obligation = Obligation {
param_env,
cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
recursion_depth: 0,
predicate: trait_ref.without_const().to_predicate(infcx.tcx),
};
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
debug!(
"type_known_to_meet_ty={:?} bound={} => {:?}",
ty,
infcx.tcx.def_path_str(def_id),
result
);
if result && ty.has_infer_types_or_consts() {
let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
infcx.tcx.def_path_str(def_id)
);
true
}
Err(e) => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
ty,
infcx.tcx.def_path_str(def_id),
e
);
false
}
}
} else {
result
}
}
fn do_normalize_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
region_context: DefId,
cause: ObligationCause<'tcx>,
elaborated_env: ty::ParamEnv<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>,
) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> {
debug!(
"do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})",
predicates, region_context, cause,
);
let span = cause.span;
tcx.infer_ctxt().enter(|infcx| {
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
let predicates =
match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
};
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
let outlives_env = OutlivesEnvironment::new(elaborated_env);
infcx.resolve_regions_and_report_errors(
region_context,
&outlives_env,
RegionckMode::default(),
);
let predicates = match infcx.fully_resolve(predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
tcx.sess.span_err(span, &fixup_err.to_string());
return Err(ErrorReported);
}
};
if predicates.needs_infer() {
tcx.sess.delay_span_bug(span, "encountered inference variables after `fully_resolve`");
Err(ErrorReported)
} else {
Ok(predicates)
}
})
}
pub fn normalize_param_env_or_error<'tcx>(
tcx: TyCtxt<'tcx>,
region_context: DefId,
unnormalized_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
) -> ty::ParamEnv<'tcx> {
debug!(
"normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})",
region_context, unnormalized_env, cause
);
let mut predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
.map(|obligation| obligation.predicate)
.collect();
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
let elaborated_env =
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
let outlives_predicates: Vec<_> = predicates
.drain_filter(|predicate| match predicate.skip_binders() {
ty::PredicateAtom::TypeOutlives(..) => true,
_ => false,
})
.collect();
debug!(
"normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
predicates, outlives_predicates
);
let non_outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
cause.clone(),
elaborated_env,
predicates,
) {
Ok(predicates) => predicates,
Err(ErrorReported) => {
debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
return elaborated_env;
}
};
debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
let outlives_env =
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
cause,
outlives_env,
outlives_predicates,
) {
Ok(predicates) => predicates,
Err(ErrorReported) => {
debug!("normalize_param_env_or_error: errored resolving outlives predicates");
return elaborated_env;
}
};
debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
let mut predicates = non_outlives_predicates;
predicates.extend(outlives_predicates);
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
}
pub fn fully_normalize<'a, 'tcx, T>(
infcx: &InferCtxt<'a, 'tcx>,
mut fulfill_cx: FulfillmentContext<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
) -> Result<T, Vec<FulfillmentError<'tcx>>>
where
T: TypeFoldable<'tcx>,
{
debug!("fully_normalize_with_fulfillcx(value={:?})", value);
let selcx = &mut SelectionContext::new(infcx);
let Normalized { value: normalized_value, obligations } =
project::normalize(selcx, param_env, cause, value);
debug!(
"fully_normalize: normalized_value={:?} obligations={:?}",
normalized_value, obligations
);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
}
debug!("fully_normalize: select_all_or_error start");
fulfill_cx.select_all_or_error(infcx)?;
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
Ok(resolved_value)
}
pub fn impossible_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>,
) -> bool {
debug!("impossible_predicates(predicates={:?})", predicates);
let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::reveal_all();
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
let cause = ObligationCause::dummy();
let Normalized { value: predicates, obligations } =
normalize(&mut selcx, param_env, cause.clone(), predicates);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
for predicate in predicates {
let obligation = Obligation::new(cause.clone(), param_env, predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
fulfill_cx.select_all_or_error(&infcx).is_err()
});
debug!("impossible_predicates = {:?}", result);
result
}
fn subst_and_check_impossible_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
key: (DefId, SubstsRef<'tcx>),
) -> bool {
debug!("subst_and_check_impossible_predicates(key={:?})", key);
let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
predicates.retain(|predicate| !predicate.needs_subst());
let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
result
}
#[inline]
fn vtable_methods<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
debug!("vtable_methods({:?})", trait_ref);
tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
let trait_methods = tcx
.associated_items(trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);
trait_methods.map(move |trait_method| {
debug!("vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;
if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
debug!("vtable_methods: not vtable safe");
return None;
}
let substs = trait_ref.map_bound(|trait_ref| {
InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize]
}
})
});
let substs =
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if impossible_predicates(tcx, predicates.predicates) {
debug!("vtable_methods: predicates do not hold");
return None;
}
Some((def_id, substs))
})
}))
}
fn type_implements_trait<'tcx>(
tcx: TyCtxt<'tcx>,
key: (
DefId,
Ty<'tcx>,
SubstsRef<'tcx>,
ParamEnv<'tcx>,
),
) -> bool {
let (trait_def_id, ty, params, param_env) = key;
debug!(
"type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
trait_def_id, ty, params, param_env
);
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
let obligation = Obligation {
cause: ObligationCause::dummy(),
param_env,
recursion_depth: 0,
predicate: trait_ref.without_const().to_predicate(tcx),
};
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
}
pub fn provide(providers: &mut ty::query::Providers) {
object_safety::provide(providers);
structural_match::provide(providers);
*providers = ty::query::Providers {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
vtable_methods,
type_implements_trait,
subst_and_check_impossible_predicates,
mir_abstract_const: |tcx, def_id| {
let def_id = def_id.expect_local();
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
tcx.mir_abstract_const_of_const_arg(def)
} else {
const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
}
},
mir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
const_evaluatable::mir_abstract_const(
tcx,
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
)
},
try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts,
..*providers
};
}