mod chalk;
pub mod query;
pub mod select;
pub mod specialization_graph;
mod structural_impls;
use crate::infer::canonical::Canonical;
use crate::mir::interpret::ErrorHandled;
use crate::ty::subst::SubstsRef;
use crate::ty::{self, AdtKind, Ty, TyCtxt};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
pub use self::ObligationCauseCode::*;
pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum Reveal {
UserFacing,
All,
}
#[derive(Clone, PartialEq, Eq, Hash, Lift)]
pub struct ObligationCause<'tcx> {
data: Option<Rc<ObligationCauseData<'tcx>>>,
}
const DUMMY_OBLIGATION_CAUSE_DATA: ObligationCauseData<'static> =
ObligationCauseData { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation };
impl<'tcx> fmt::Debug for ObligationCause<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ObligationCauseData::fmt(self, f)
}
}
impl Deref for ObligationCause<'tcx> {
type Target = ObligationCauseData<'tcx>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.data.as_deref().unwrap_or(&DUMMY_OBLIGATION_CAUSE_DATA)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct ObligationCauseData<'tcx> {
pub span: Span,
pub body_id: hir::HirId,
pub code: ObligationCauseCode<'tcx>,
}
impl<'tcx> ObligationCause<'tcx> {
#[inline]
pub fn new(
span: Span,
body_id: hir::HirId,
code: ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {
ObligationCause { data: Some(Rc::new(ObligationCauseData { span, body_id, code })) }
}
pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
ObligationCause::new(span, body_id, MiscObligation)
}
pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
ObligationCause::new(span, hir::CRATE_HIR_ID, MiscObligation)
}
#[inline(always)]
pub fn dummy() -> ObligationCause<'tcx> {
ObligationCause { data: None }
}
pub fn make_mut(&mut self) -> &mut ObligationCauseData<'tcx> {
Rc::make_mut(self.data.get_or_insert_with(|| Rc::new(DUMMY_OBLIGATION_CAUSE_DATA)))
}
pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
match self.code {
ObligationCauseCode::CompareImplMethodObligation { .. }
| ObligationCauseCode::MainFunctionType
| ObligationCauseCode::StartFunctionType => {
tcx.sess.source_map().guess_head_span(self.span)
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span,
..
}) => arm_span,
_ => self.span,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct UnifyReceiverContext<'tcx> {
pub assoc_item: ty::AssocItem,
pub param_env: ty::ParamEnv<'tcx>,
pub substs: SubstsRef<'tcx>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub enum ObligationCauseCode<'tcx> {
MiscObligation,
SliceOrArrayElem,
TupleElem,
ProjectionWf(ty::ProjectionTy<'tcx>),
ItemObligation(DefId),
BindingObligation(DefId, Span),
ReferenceOutlivesReferent(Ty<'tcx>),
ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
ObjectCastObligation( Ty<'tcx>),
Coercion {
source: Ty<'tcx>,
target: Ty<'tcx>,
},
AssignmentLhsSized,
TupleInitializerSized,
StructInitializerSized,
VariableType(hir::HirId),
SizedArgumentType(Option<Span>),
SizedReturnType,
SizedYieldType,
InlineAsmSized,
RepeatVec(bool),
FieldSized {
adt_kind: AdtKind,
span: Span,
last: bool,
},
ConstSized,
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
DerivedObligation(DerivedObligationCause<'tcx>),
CompareImplConstObligation,
CompareImplMethodObligation {
item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
CompareImplTypeObligation {
item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
ExprAssignable,
MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
Pattern {
span: Option<Span>,
root_ty: Ty<'tcx>,
origin_expr: bool,
},
ConstPatternStructural,
IfExpression(Box<IfExpressionCause>),
IfExpressionWithNoElse,
MainFunctionType,
StartFunctionType,
IntrinsicType,
MethodReceiver,
UnifyReceiver(Box<UnifyReceiverContext<'tcx>>),
ReturnNoExpression,
ReturnValue(hir::HirId),
ReturnType,
BlockTailExpression(hir::HirId),
TrivialBound,
}
impl ObligationCauseCode<'_> {
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;
while let BuiltinDerivedObligation(cause)
| ImplDerivedObligation(cause)
| DerivedObligation(cause) = base_cause
{
base_cause = &cause.parent_code;
}
base_cause
}
}
#[cfg(target_arch = "x86_64")]
static_assert_size!(ObligationCauseCode<'_>, 32);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum StatementAsExpression {
CorrectType,
NeedsBoxing,
}
impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
type Lifted = StatementAsExpression;
fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
Some(self)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span,
pub scrut_span: Span,
pub semi_span: Option<(Span, StatementAsExpression)>,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
pub scrut_hir_id: hir::HirId,
pub opt_suggest_box_span: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IfExpressionCause {
pub then: Span,
pub else_sp: Span,
pub outer: Option<Span>,
pub semicolon: Option<(Span, StatementAsExpression)>,
pub opt_suggest_box_span: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct DerivedObligationCause<'tcx> {
pub parent_trait_ref: ty::PolyTraitRef<'tcx>,
pub parent_code: Rc<ObligationCauseCode<'tcx>>,
}
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum SelectionError<'tcx> {
Unimplemented,
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
TraitNotObjectSafe(DefId),
ConstEvalFailure(ErrorHandled),
Overflow,
}
pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub enum ImplSource<'tcx, N> {
UserDefined(ImplSourceUserDefinedData<'tcx, N>),
AutoImpl(ImplSourceAutoImplData<N>),
Param(Vec<N>),
Object(ImplSourceObjectData<'tcx, N>),
Builtin(ImplSourceBuiltinData<N>),
Closure(ImplSourceClosureData<'tcx, N>),
FnPointer(ImplSourceFnPointerData<'tcx, N>),
DiscriminantKind(ImplSourceDiscriminantKindData),
Generator(ImplSourceGeneratorData<'tcx, N>),
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
}
impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {
ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n) => n,
ImplSource::Builtin(i) => i.nested,
ImplSource::AutoImpl(d) => d.nested,
ImplSource::Closure(c) => c.nested,
ImplSource::Generator(c) => c.nested,
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
}
}
pub fn borrow_nested_obligations(&self) -> &[N] {
match &self {
ImplSource::UserDefined(i) => &i.nested[..],
ImplSource::Param(n) => &n[..],
ImplSource::Builtin(i) => &i.nested[..],
ImplSource::AutoImpl(d) => &d.nested[..],
ImplSource::Closure(c) => &c.nested[..],
ImplSource::Generator(c) => &c.nested[..],
ImplSource::Object(d) => &d.nested[..],
ImplSource::FnPointer(d) => &d.nested[..],
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
ImplSource::TraitAlias(d) => &d.nested[..],
}
}
pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M>
where
F: FnMut(N) -> M,
{
match self {
ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData {
impl_def_id: i.impl_def_id,
substs: i.substs,
nested: i.nested.into_iter().map(f).collect(),
}),
ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()),
ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
nested: i.nested.into_iter().map(f).collect(),
}),
ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
upcast_trait_ref: o.upcast_trait_ref,
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData {
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData {
fn_ty: p.fn_ty,
nested: p.nested.into_iter().map(f).collect(),
}),
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
}
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
nested: d.nested.into_iter().map(f).collect(),
}),
}
}
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceUserDefinedData<'tcx, N> {
pub impl_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceGeneratorData<'tcx, N> {
pub generator_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceClosureData<'tcx, N> {
pub closure_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceBuiltinData<N> {
pub nested: Vec<N>,
}
#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceObjectData<'tcx, N> {
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
pub vtable_base: usize,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceFnPointerData<'tcx, N> {
pub fn_ty: Ty<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub struct ImplSourceDiscriminantKindData;
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
pub enum ObjectSafetyViolation {
SizedSelf(SmallVec<[Span; 1]>),
SupertraitSelf(SmallVec<[Span; 1]>),
Method(Symbol, MethodViolationCode, Span),
AssocConst(Symbol, Span),
}
impl ObjectSafetyViolation {
pub fn error_msg(&self) -> Cow<'static, str> {
match *self {
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
ObjectSafetyViolation::SupertraitSelf(ref spans) => {
if spans.iter().any(|sp| *sp != DUMMY_SP) {
"it uses `Self` as a type parameter".into()
} else {
"it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
.into()
}
}
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_, _, _), _) => {
format!("associated function `{}` has no `self` parameter", name).into()
}
ObjectSafetyViolation::Method(
name,
MethodViolationCode::ReferencesSelfInput(_),
DUMMY_SP,
) => format!("method `{}` references the `Self` type in its parameters", name).into(),
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
format!("method `{}` references the `Self` type in this parameter", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
format!("method `{}` references the `Self` type in its return type", name).into()
}
ObjectSafetyViolation::Method(
name,
MethodViolationCode::WhereClauseReferencesSelf,
_,
) => {
format!("method `{}` references the `Self` type in its `where` clause", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
format!("method `{}` has generic type parameters", name).into()
}
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
}
ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
format!("it contains associated `const` `{}`", name).into()
}
ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
}
}
pub fn solution(&self, err: &mut DiagnosticBuilder<'_>) {
match *self {
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
ObjectSafetyViolation::Method(
name,
MethodViolationCode::StaticMethod(sugg, self_span, has_args),
_,
) => {
err.span_suggestion(
self_span,
&format!(
"consider turning `{}` into a method by giving it a `&self` argument",
name
),
format!("&self{}", if has_args { ", " } else { "" }),
Applicability::MaybeIncorrect,
);
match sugg {
Some((sugg, span)) => {
err.span_suggestion(
span,
&format!(
"alternatively, consider constraining `{}` so it does not apply to \
trait objects",
name
),
sugg.to_string(),
Applicability::MaybeIncorrect,
);
}
None => {
err.help(&format!(
"consider turning `{}` into a method by giving it a `&self` \
argument or constraining it so it does not apply to trait objects",
name
));
}
}
}
ObjectSafetyViolation::Method(
name,
MethodViolationCode::UndispatchableReceiver,
span,
) => {
err.span_suggestion(
span,
&format!(
"consider changing method `{}`'s `self` parameter to be `&self`",
name
),
"&Self".to_string(),
Applicability::MachineApplicable,
);
}
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
err.help(&format!("consider moving `{}` to another trait", name));
}
}
}
pub fn spans(&self) -> SmallVec<[Span; 1]> {
match self {
ObjectSafetyViolation::SupertraitSelf(spans)
| ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
ObjectSafetyViolation::AssocConst(_, span)
| ObjectSafetyViolation::Method(_, _, span)
if *span != DUMMY_SP =>
{
smallvec![*span]
}
_ => smallvec![],
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
pub enum MethodViolationCode {
StaticMethod(Option<(&'static str, Span)>, Span, bool ),
ReferencesSelfInput(usize),
ReferencesSelfOutput,
WhereClauseReferencesSelf,
Generic,
UndispatchableReceiver,
}