//! Contains the definition for the "Rust IR" -- this is basically a "lowered" //! version of the AST, roughly corresponding to [the HIR] in the Rust //! compiler. use chalk_derive::{Fold, HasInterner, Visit}; use chalk_ir::cast::Cast; use chalk_ir::fold::shift::Shift; use chalk_ir::interner::Interner; use chalk_ir::{ try_break, visit::Visit, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, Ty, TyKind, VariableKind, WhereClause, WithKind, }; use std::iter; use std::ops::ControlFlow; /// Identifier for an "associated type value" found in some impl. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssociatedTyValueId(pub I::DefId); chalk_ir::id_visit!(AssociatedTyValueId); chalk_ir::id_fold!(AssociatedTyValueId); #[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct ImplDatum { pub polarity: Polarity, pub binders: Binders>, pub impl_type: ImplType, pub associated_ty_value_ids: Vec>, } impl ImplDatum { pub fn is_positive(&self) -> bool { self.polarity.is_positive() } pub fn trait_id(&self) -> TraitId { self.binders.skip_binders().trait_ref.trait_id } pub fn self_type_adt_id(&self, interner: I) -> Option> { match self .binders .skip_binders() .trait_ref .self_type_parameter(interner) .kind(interner) { TyKind::Adt(id, _) => Some(*id), _ => None, } } } #[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Fold, Visit)] pub struct ImplDatumBound { pub trait_ref: TraitRef, pub where_clauses: Vec>, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ImplType { Local, External, } chalk_ir::const_visit!(ImplType); #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DefaultImplDatum { pub binders: Binders>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner)] pub struct DefaultImplDatumBound { pub trait_ref: TraitRef, pub accessible_tys: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct AdtDatum { pub binders: Binders>, pub id: AdtId, pub flags: AdtFlags, pub kind: AdtKind, } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum AdtKind { Struct, Enum, Union, } chalk_ir::const_visit!(AdtKind); #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct AdtDatumBound { pub variants: Vec>, pub where_clauses: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct AdtVariantDatum { pub fields: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AdtFlags { pub upstream: bool, pub fundamental: bool, pub phantom_data: bool, } chalk_ir::const_visit!(AdtFlags); #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AdtRepr { pub c: bool, pub packed: bool, pub int: Option>, } /// Information about the size and alignment of an ADT. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AdtSizeAlign { one_zst: bool, } impl AdtSizeAlign { pub fn from_one_zst(one_zst: bool) -> AdtSizeAlign { AdtSizeAlign { one_zst } } pub fn one_zst(&self) -> bool { self.one_zst } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate represention (rust_ir) of a function definition/declaration. /// For example, in the following rust code: /// /// ```ignore /// fn foo() -> i32 where T: Eq; /// ``` /// /// This would represent the declaration of `foo`. /// /// Note this is distinct from a function pointer, which points to /// a function with a given type signature, whereas this represents /// a specific function definition. pub struct FnDefDatum { pub id: FnDefId, pub sig: chalk_ir::FnSig, pub binders: Binders>, } /// Avoids visiting `I::FnAbi` impl Visit for FnDefDatum { fn visit_with( &self, visitor: &mut dyn chalk_ir::visit::Visitor, outer_binder: DebruijnIndex, ) -> ControlFlow { try_break!(self.id.visit_with(visitor, outer_binder)); self.binders.visit_with(visitor, outer_binder) } } /// Represents the inputs and outputs on a `FnDefDatum`. This is split /// from the where clauses, since these can contain bound lifetimes. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct FnDefInputsAndOutputDatum { /// Types of the function's arguments /// ```ignore /// fn foo(bar: i32, baz: T); /// ^^^ ^ /// ``` /// pub argument_types: Vec>, /// Return type of the function /// ```ignore /// fn foo() -> i32; /// ^^^ /// ``` pub return_type: Ty, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] /// Represents the bounds on a `FnDefDatum`, including /// the function definition's type signature and where clauses. pub struct FnDefDatumBound { /// Inputs and outputs defined on a function /// These are needed for late-bound regions in rustc. For example the /// lifetime `'a` in /// ```ignore /// fn foo<'a, T>(&'a T); /// ^^ /// ``` /// Rustc doesn't pass in late-bound the regions in substs, but the inputs /// and outputs may use them. `where_clauses` don't need an extra set of /// `Binders`, since any lifetimes found in where clauses are not late-bound. /// /// For more information, see [this rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/early-late-bound.html). pub inputs_and_output: Binders>, /// Where clauses defined on the function /// ```ignore /// fn foo() where T: Eq; /// ^^^^^^^^^^^ /// ``` pub where_clauses: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate representation (rust_ir) of a Trait Definition. For /// example, given the following rust code: /// /// ```compile_fail /// use std::fmt::Debug; /// /// trait Foo /// where /// T: Debug, /// { /// type Bar; /// } /// ``` /// /// This would represent the `trait Foo` declaration. Note that the details of /// the trait members (e.g., the associated type declaration (`type Bar`) are /// not contained in this type, and are represented separately (e.g., in /// [`AssociatedTyDatum`]). /// /// Not to be confused with the rust_ir for a Trait Implementation, which is /// represented by [`ImplDatum`] /// /// [`ImplDatum`]: struct.ImplDatum.html /// [`AssociatedTyDatum`]: struct.AssociatedTyDatum.html #[derive(Visit)] pub struct TraitDatum { pub id: TraitId, pub binders: Binders>, /// "Flags" indicate special kinds of traits, like auto traits. /// In Rust syntax these are represented in different ways, but in /// chalk we add annotations like `#[auto]`. pub flags: TraitFlags, pub associated_ty_ids: Vec>, /// If this is a well-known trait, which one? If `None`, this is a regular, /// user-defined trait. pub well_known: Option, } /// A list of the traits that are "well known" to chalk, which means that /// the chalk-solve crate has special, hard-coded impls for them. #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum WellKnownTrait { Sized, Copy, Clone, Drop, /// The trait `FnOnce` - the generic argument `Args` is always a tuple /// corresponding to the arguments of a function implementing this trait. /// E.g. `fn(u8, bool): FnOnce<(u8, bool)>` FnOnce, FnMut, Fn, Unsize, Unpin, CoerceUnsized, DiscriminantKind, Generator, DispatchFromDyn, } chalk_ir::const_visit!(WellKnownTrait); impl TraitDatum { pub fn is_auto_trait(&self) -> bool { self.flags.auto } pub fn is_non_enumerable_trait(&self) -> bool { self.flags.non_enumerable } pub fn is_coinductive_trait(&self) -> bool { self.flags.coinductive } /// Gives access to the where clauses of the trait, quantified over the type parameters of the trait: /// /// ```ignore /// trait Foo where T: Debug { } /// ^^^^^^^^^^^^^^ /// ``` pub fn where_clauses(&self) -> Binders<&Vec>> { self.binders.as_ref().map(|td| &td.where_clauses) } } #[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Visit)] pub struct TraitDatumBound { /// Where clauses defined on the trait: /// /// ```ignore /// trait Foo where T: Debug { } /// ^^^^^^^^^^^^^^ /// ``` pub where_clauses: Vec>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct TraitFlags { /// An "auto trait" is one that is "automatically implemented" for every /// struct, so long as no explicit impl is given. /// /// Examples are `Send` and `Sync`. pub auto: bool, pub marker: bool, /// Indicate that a trait is defined upstream (in a dependency), used during /// coherence checking. pub upstream: bool, /// A fundamental trait is a trait where adding an impl for an existing type /// is considered a breaking change. Examples of fundamental traits are the /// closure traits like `Fn` and `FnMut`. /// /// As of this writing (2020-03-27), fundamental traits are declared by the /// unstable `#[fundamental]` attribute in rustc, and hence cannot appear /// outside of the standard library. pub fundamental: bool, /// Indicates that chalk cannot list all of the implementations of the given /// trait, likely because it is a publicly exported trait in a library. /// /// Currently (2020-03-27) rustc and rust-analyzer mark all traits as /// non_enumerable, and in the future it may become the only option. pub non_enumerable: bool, pub coinductive: bool, } chalk_ir::const_visit!(TraitFlags); /// An inline bound, e.g. `: Foo` in `impl> SomeType`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub enum InlineBound { TraitBound(TraitBound), AliasEqBound(AliasEqBound), } #[allow(type_alias_bounds)] pub type QuantifiedInlineBound = Binders>; pub trait IntoWhereClauses { type Output; fn into_where_clauses(&self, interner: I, self_ty: Ty) -> Vec; } impl IntoWhereClauses for InlineBound { type Output = WhereClause; /// Applies the `InlineBound` to `self_ty` and lowers to a /// [`chalk_ir::DomainGoal`]. /// /// Because an `InlineBound` does not know anything about what it's binding, /// you must provide that type as `self_ty`. fn into_where_clauses(&self, interner: I, self_ty: Ty) -> Vec> { match self { InlineBound::TraitBound(b) => b.into_where_clauses(interner, self_ty), InlineBound::AliasEqBound(b) => b.into_where_clauses(interner, self_ty), } } } impl IntoWhereClauses for QuantifiedInlineBound { type Output = QuantifiedWhereClause; fn into_where_clauses(&self, interner: I, self_ty: Ty) -> Vec> { let self_ty = self_ty.shifted_in(interner); self.map_ref(|b| b.into_where_clauses(interner, self_ty)) .into_iter() .collect() } } /// Represents a trait bound on e.g. a type or type parameter. /// Does not know anything about what it's binding. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct TraitBound { pub trait_id: TraitId, pub args_no_self: Vec>, } impl TraitBound { fn into_where_clauses(&self, interner: I, self_ty: Ty) -> Vec> { let trait_ref = self.as_trait_ref(interner, self_ty); vec![WhereClause::Implemented(trait_ref)] } pub fn as_trait_ref(&self, interner: I, self_ty: Ty) -> TraitRef { TraitRef { trait_id: self.trait_id, substitution: Substitution::from_iter( interner, iter::once(self_ty.cast(interner)).chain(self.args_no_self.iter().cloned()), ), } } } /// Represents an alias equality bound on e.g. a type or type parameter. /// Does not know anything about what it's binding. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct AliasEqBound { pub trait_bound: TraitBound, pub associated_ty_id: AssocTypeId, /// Does not include trait parameters. pub parameters: Vec>, pub value: Ty, } impl AliasEqBound { fn into_where_clauses(&self, interner: I, self_ty: Ty) -> Vec> { let trait_ref = self.trait_bound.as_trait_ref(interner, self_ty); let substitution = Substitution::from_iter( interner, self.parameters .iter() .cloned() .chain(trait_ref.substitution.iter(interner).cloned()), ); vec![ WhereClause::Implemented(trait_ref), WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(ProjectionTy { associated_ty_id: self.associated_ty_id, substitution, }), ty: self.value.clone(), }), ] } } pub trait Anonymize { /// Utility function that converts from a list of generic arguments /// which *have* associated data (`WithKind`) to a list of /// "anonymous" generic parameters that just preserves their /// kinds (`VariableKind`). Often convenient in lowering. fn anonymize(&self) -> Vec>; } impl Anonymize for [WithKind] { fn anonymize(&self) -> Vec> { self.iter().map(|pk| pk.kind.clone()).collect() } } /// Represents an associated type declaration found inside of a trait: /// /// ```notrust /// trait Foo { // P0 is Self /// type Bar: [bounds] /// where /// [where_clauses]; /// } /// ``` /// /// The meaning of each of these parts: /// /// * The *parameters* `P0...Pm` are all in scope for this associated type. /// * The *bounds* `bounds` are things that the impl must prove to be true. /// * The *where clauses* `where_clauses` are things that the impl can *assume* to be true /// (but which projectors must prove). #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AssociatedTyDatum { /// The trait this associated type is defined in. pub trait_id: TraitId, /// The ID of this associated type pub id: AssocTypeId, /// Name of this associated type. pub name: I::Identifier, /// These binders represent the `P0...Pm` variables. The binders /// are in the order `[Pn..Pm; P0..Pn]`. That is, the variables /// from `Bar` come first (corresponding to the de bruijn concept /// that "inner" binders are lower indices, although within a /// given binder we do not have an ordering). pub binders: Binders>, } // Manual implementation to avoid I::Identifier type. impl Visit for AssociatedTyDatum { fn visit_with( &self, visitor: &mut dyn chalk_ir::visit::Visitor, outer_binder: DebruijnIndex, ) -> ControlFlow { try_break!(self.trait_id.visit_with(visitor, outer_binder)); try_break!(self.id.visit_with(visitor, outer_binder)); self.binders.visit_with(visitor, outer_binder) } } /// Encodes the parts of `AssociatedTyDatum` where the parameters /// `P0..Pm` are in scope (`bounds` and `where_clauses`). #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct AssociatedTyDatumBound { /// Bounds on the associated type itself. /// /// These must be proven by the implementer, for all possible parameters that /// would result in a well-formed projection. pub bounds: Vec>, /// Where clauses that must hold for the projection to be well-formed. pub where_clauses: Vec>, } impl AssociatedTyDatum { /// Returns the associated ty's bounds applied to the projection type, e.g.: /// /// ```notrust /// Implemented(::Item: Sized) /// ``` /// /// these quantified where clauses are in the scope of the /// `binders` field. pub fn bounds_on_self(&self, interner: I) -> Vec> { let (binders, assoc_ty_datum) = self.binders.as_ref().into(); // Create a list `P0...Pn` of references to the binders in // scope for this associated type: let substitution = Substitution::from_iter( interner, binders .iter(interner) .enumerate() .map(|p| p.to_generic_arg(interner)), ); // The self type will be `>::Item` etc let self_ty = TyKind::Alias(AliasTy::Projection(ProjectionTy { associated_ty_id: self.id, substitution, })) .intern(interner); // Now use that as the self type for the bounds, transforming // something like `type Bar: Debug` into // // ``` // >::Item: Debug // ``` assoc_ty_datum .bounds .iter() .flat_map(|b| b.into_where_clauses(interner, self_ty.clone())) .collect() } } /// Represents the *value* of an associated type that is assigned /// from within some impl. /// /// ```ignore /// impl Iterator for Foo { /// type Item = XXX; // <-- represents this line! /// } /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct AssociatedTyValue { /// Impl in which this associated type value is found. You might /// need to look at this to find the generic parameters defined on /// the impl, for example. /// /// ```ignore /// impl Iterator for Foo { // <-- refers to this impl /// type Item = XXX; // <-- (where this is self) /// } /// ``` pub impl_id: ImplId, /// Associated type being defined. /// /// ```ignore /// impl Iterator for Foo { /// type Item = XXX; // <-- (where this is self) /// } /// ... /// trait Iterator { /// type Item; // <-- refers to this declaration here! /// } /// ``` pub associated_ty_id: AssocTypeId, /// Additional binders declared on the associated type itself, /// beyond those from the impl. This would be empty for normal /// associated types, but non-empty for generic associated types. /// /// ```ignore /// impl Iterable for Vec { /// type Iter<'a> = vec::Iter<'a, T>; /// // ^^^^ refers to these generics here /// } /// ``` pub value: Binders>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct AssociatedTyValueBound { /// Type that we normalize to. The X in `type Foo<'a> = X`. pub ty: Ty, } /// Represents the bounds for an `impl Trait` type. /// /// ```ignore /// opaque type T: A + B = HiddenTy; /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct OpaqueTyDatum { /// The placeholder `!T` that corresponds to the opaque type `T`. pub opaque_ty_id: OpaqueTyId, /// The type bound to when revealed. pub bound: Binders>, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct OpaqueTyDatumBound { /// Trait bounds for the opaque type. These are bounds that the hidden type must meet. pub bounds: Binders>>, /// Where clauses that inform well-formedness conditions for the opaque type. /// These are conditions on the generic parameters of the opaque type which must be true /// for a reference to the opaque type to be well-formed. pub where_clauses: Binders>>, } // The movability of a generator: whether a generator contains self-references, // causing it to be !Unpin #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Movability { Static, Movable, } chalk_ir::copy_fold!(Movability); /// Represents a generator type. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] pub struct GeneratorDatum { // Can the generator be moved (is Unpin or not) pub movability: Movability, /// All of the nested types for this generator. The `Binder` /// represents the types and lifetimes that this generator is generic over - /// this behaves in the same way as `AdtDatum.binders` pub input_output: Binders>, } /// The nested types for a generator. This always appears inside a `GeneratorDatum` #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] pub struct GeneratorInputOutputDatum { /// The generator resume type - a value of this type /// is supplied by the caller when resuming the generator. /// Currently, this plays no rule in goal resolution. pub resume_type: Ty, /// The generator yield type - a value of this type /// is supplied by the generator during a yield. /// Currently, this plays no role in goal resolution. pub yield_type: Ty, /// The generator return type - a value of this type /// is supplied by the generator when it returns. /// Currently, this plays no role in goal resolution pub return_type: Ty, /// The upvars stored by the generator. These represent /// types captured from the generator's environment, /// and are stored across all yields. These types (along with the witness types) /// are considered 'constituent types' for the purposes of determining auto trait /// implementations - that its, a generator impls an auto trait A /// iff all of its constituent types implement A. pub upvars: Vec>, } /// The generator witness data. Each `GeneratorId` has both a `GeneratorDatum` /// and a `GeneratorWitnessDatum` - these represent two distinct types in Rust. /// `GeneratorWitnessDatum` is logically 'inside' a generator - this only /// matters when we treat the witness type as a 'constituent type for the /// purposes of determining auto trait implementations. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] pub struct GeneratorWitnessDatum { /// This binder is identical to the `input_output` binder in `GeneratorWitness` - /// it binds the types and lifetimes that the generator is generic over. /// There is an additional binder inside `GeneratorWitnessExistential`, which /// is treated specially. pub inner_types: Binders>, } /// The generator witness types, together with existentially bound lifetimes. /// Each 'witness type' represents a type stored inside the generator across /// a yield. When a generator type is constructed, the precise region relationships /// found in the generator body are erased. As a result, we are left with existential /// lifetimes - each type is parameterized over *some* lifetimes, but we do not /// know their precise values. /// /// Unlike the binder in `GeneratorWitnessDatum`, this `Binder` never gets substituted /// via an `Ty`. Instead, we handle this `Binders` specially when determining /// auto trait impls. See `push_auto_trait_impls_generator_witness` for more details. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] pub struct GeneratorWitnessExistential { pub types: Binders>>, } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub enum Polarity { Positive, Negative, } chalk_ir::const_visit!(Polarity); impl Polarity { pub fn is_positive(&self) -> bool { match *self { Polarity::Positive => true, Polarity::Negative => false, } } } /// Indicates the "most permissive" Fn-like trait that the closure implements. /// If the closure kind for a closure is FnMut, for example, then the closure /// implements FnMut and FnOnce. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub enum ClosureKind { Fn, FnMut, FnOnce, }