pub mod lift;
pub mod visit;
use std::{borrow::Cow, fmt};
use flux_common::{bug, span_bug};
use flux_rustc_bridge::def_id_to_string;
use flux_syntax::surface::ParamMode;
pub use flux_syntax::surface::{BinOp, UnOp};
use itertools::Itertools;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_hash::FxHashMap;
pub use rustc_hir::PrimTy;
use rustc_hir::{
def::DefKind,
def_id::{DefId, LocalDefId},
FnHeader, OwnerId, ParamName, Safety,
};
use rustc_index::newtype_index;
use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
pub use rustc_middle::mir::Mutability;
use rustc_middle::{middle::resolve_bound_vars::ResolvedArg, ty::TyCtxt};
use rustc_span::{symbol::Ident, Span, Symbol};
pub use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use crate::MaybeExternId;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Ignored {
Yes,
No,
}
impl Ignored {
pub fn to_bool(self) -> bool {
match self {
Ignored::Yes => true,
Ignored::No => false,
}
}
}
impl From<bool> for Ignored {
fn from(value: bool) -> Self {
if value {
Ignored::Yes
} else {
Ignored::No
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Trusted {
Yes,
No,
}
impl Trusted {
pub fn to_bool(self) -> bool {
match self {
Trusted::Yes => true,
Trusted::No => false,
}
}
}
impl From<bool> for Trusted {
fn from(value: bool) -> Self {
if value {
Trusted::Yes
} else {
Trusted::No
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum CheckOverflow {
Yes,
No,
}
impl CheckOverflow {
pub fn to_bool(self) -> bool {
match self {
CheckOverflow::Yes => true,
CheckOverflow::No => false,
}
}
}
impl From<bool> for CheckOverflow {
fn from(value: bool) -> Self {
if value {
CheckOverflow::Yes
} else {
CheckOverflow::No
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Generics<'fhir> {
pub params: &'fhir [GenericParam<'fhir>],
pub refinement_params: &'fhir [RefineParam<'fhir>],
pub predicates: &'fhir [WhereBoundPredicate<'fhir>],
}
#[derive(Debug, Clone, Copy)]
pub struct GenericParam<'fhir> {
pub def_id: MaybeExternId,
pub name: ParamName,
pub kind: GenericParamKind<'fhir>,
}
#[derive(Debug, Clone, Copy)]
pub enum GenericParamKind<'fhir> {
Type { default: Option<Ty<'fhir>> },
Lifetime,
Const { ty: Ty<'fhir> },
}
#[derive(Debug)]
pub struct Qualifier<'fhir> {
pub name: Symbol,
pub args: &'fhir [RefineParam<'fhir>],
pub expr: Expr<'fhir>,
pub global: bool,
}
#[derive(Clone, Copy, Debug)]
pub enum Node<'fhir> {
Item(&'fhir Item<'fhir>),
TraitItem(&'fhir TraitItem<'fhir>),
ImplItem(&'fhir ImplItem<'fhir>),
OpaqueTy(&'fhir OpaqueTy<'fhir>),
}
impl<'fhir> Node<'fhir> {
pub fn as_owner(self) -> Option<OwnerNode<'fhir>> {
match self {
Node::Item(item) => Some(OwnerNode::Item(item)),
Node::TraitItem(trait_item) => Some(OwnerNode::TraitItem(trait_item)),
Node::ImplItem(impl_item) => Some(OwnerNode::ImplItem(impl_item)),
Node::OpaqueTy(_) => None,
}
}
pub fn expect_opaque_ty(&self) -> &'fhir OpaqueTy<'fhir> {
if let Node::OpaqueTy(opaque_ty) = &self {
opaque_ty
} else {
bug!("expected opaque type")
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum OwnerNode<'fhir> {
Item(&'fhir Item<'fhir>),
TraitItem(&'fhir TraitItem<'fhir>),
ImplItem(&'fhir ImplItem<'fhir>),
}
impl<'fhir> OwnerNode<'fhir> {
pub fn fn_sig(&self) -> Option<&'fhir FnSig<'fhir>> {
match self {
OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, ..), .. })
| OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig), .. })
| OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig), .. }) => Some(fn_sig),
_ => None,
}
}
pub fn generics(self) -> &'fhir Generics<'fhir> {
match self {
OwnerNode::Item(item) => &item.generics,
OwnerNode::TraitItem(trait_item) => &trait_item.generics,
OwnerNode::ImplItem(impl_item) => &impl_item.generics,
}
}
pub fn owner_id(&self) -> MaybeExternId<OwnerId> {
match self {
OwnerNode::Item(item) => item.owner_id,
OwnerNode::TraitItem(trait_item) => trait_item.owner_id,
OwnerNode::ImplItem(impl_item) => impl_item.owner_id,
}
}
}
#[derive(Debug)]
pub struct Item<'fhir> {
pub owner_id: MaybeExternId<OwnerId>,
pub generics: Generics<'fhir>,
pub kind: ItemKind<'fhir>,
}
impl<'fhir> Item<'fhir> {
pub fn expect_enum(&self) -> &EnumDef<'fhir> {
if let ItemKind::Enum(enum_def) = &self.kind {
enum_def
} else {
bug!("expected enum")
}
}
pub fn expect_struct(&self) -> &StructDef<'fhir> {
if let ItemKind::Struct(struct_def) = &self.kind {
struct_def
} else {
bug!("expected struct")
}
}
pub fn expect_type_alias(&self) -> &TyAlias<'fhir> {
if let ItemKind::TyAlias(ty_alias) = &self.kind {
ty_alias
} else {
bug!("expected type alias")
}
}
pub fn expect_impl(&self) -> &Impl<'fhir> {
if let ItemKind::Impl(impl_) = &self.kind {
impl_
} else {
bug!("expected impl")
}
}
pub fn expect_trait(&self) -> &Trait<'fhir> {
if let ItemKind::Trait(trait_) = &self.kind {
trait_
} else {
bug!("expected trait")
}
}
}
#[derive(Debug)]
pub enum ItemKind<'fhir> {
Enum(EnumDef<'fhir>),
Struct(StructDef<'fhir>),
TyAlias(TyAlias<'fhir>),
Trait(Trait<'fhir>),
Impl(Impl<'fhir>),
Fn(FnSig<'fhir>),
}
#[derive(Debug)]
pub struct TraitItem<'fhir> {
pub owner_id: MaybeExternId<OwnerId>,
pub generics: Generics<'fhir>,
pub kind: TraitItemKind<'fhir>,
}
#[derive(Debug)]
pub enum TraitItemKind<'fhir> {
Fn(FnSig<'fhir>),
Type,
}
#[derive(Debug)]
pub struct ImplItem<'fhir> {
pub owner_id: MaybeExternId<OwnerId>,
pub kind: ImplItemKind<'fhir>,
pub generics: Generics<'fhir>,
}
#[derive(Debug)]
pub enum ImplItemKind<'fhir> {
Fn(FnSig<'fhir>),
Type,
}
#[derive(Debug)]
pub enum FluxItem<'fhir> {
Qualifier(Qualifier<'fhir>),
Func(SpecFunc<'fhir>),
}
impl FluxItem<'_> {
pub fn name(&self) -> Symbol {
match self {
FluxItem::Qualifier(qual) => qual.name,
FluxItem::Func(func) => func.name,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SortDecl {
pub name: Symbol,
pub span: Span,
}
pub type SortDecls = FxHashMap<Symbol, SortDecl>;
#[derive(Debug, Clone, Copy)]
pub struct WhereBoundPredicate<'fhir> {
pub span: Span,
pub bounded_ty: Ty<'fhir>,
pub bounds: GenericBounds<'fhir>,
}
pub type GenericBounds<'fhir> = &'fhir [GenericBound<'fhir>];
#[derive(Debug, Clone, Copy)]
pub enum GenericBound<'fhir> {
Trait(PolyTraitRef<'fhir>),
Outlives(Lifetime),
}
#[derive(Debug, Clone, Copy)]
pub struct PolyTraitRef<'fhir> {
pub bound_generic_params: &'fhir [GenericParam<'fhir>],
pub modifiers: TraitBoundModifier,
pub trait_ref: Path<'fhir>,
pub span: Span,
}
#[derive(Debug, Copy, Clone)]
pub enum TraitBoundModifier {
None,
Maybe,
}
#[derive(Debug)]
pub struct Trait<'fhir> {
pub assoc_refinements: &'fhir [TraitAssocReft<'fhir>],
}
impl<'fhir> Trait<'fhir> {
pub fn find_assoc_reft(&self, name: Symbol) -> Option<&'fhir TraitAssocReft<'fhir>> {
self.assoc_refinements
.iter()
.find(|assoc_reft| assoc_reft.name == name)
}
}
#[derive(Debug, Clone, Copy)]
pub struct TraitAssocReft<'fhir> {
pub name: Symbol,
pub params: &'fhir [RefineParam<'fhir>],
pub output: Sort<'fhir>,
pub body: Option<Expr<'fhir>>,
pub span: Span,
}
#[derive(Debug)]
pub struct Impl<'fhir> {
pub assoc_refinements: &'fhir [ImplAssocReft<'fhir>],
}
impl<'fhir> Impl<'fhir> {
pub fn find_assoc_reft(&self, name: Symbol) -> Option<&'fhir ImplAssocReft<'fhir>> {
self.assoc_refinements
.iter()
.find(|assoc_reft| assoc_reft.name == name)
}
}
#[derive(Clone, Copy, Debug)]
pub struct ImplAssocReft<'fhir> {
pub name: Symbol,
pub params: &'fhir [RefineParam<'fhir>],
pub output: Sort<'fhir>,
pub body: Expr<'fhir>,
pub span: Span,
}
#[derive(Debug)]
pub struct OpaqueTy<'fhir> {
pub def_id: MaybeExternId,
pub bounds: GenericBounds<'fhir>,
}
pub type Arena = bumpalo::Bump;
#[derive(Default)]
pub struct FluxItems<'fhir> {
pub items: FxHashMap<Symbol, FluxItem<'fhir>>,
}
impl FluxItems<'_> {
pub fn new() -> Self {
Self { items: Default::default() }
}
}
#[derive(Debug)]
pub struct TyAlias<'fhir> {
pub index: Option<RefineParam<'fhir>>,
pub ty: Ty<'fhir>,
pub span: Span,
pub lifted: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct StructDef<'fhir> {
pub refined_by: &'fhir RefinedBy<'fhir>,
pub params: &'fhir [RefineParam<'fhir>],
pub kind: StructKind<'fhir>,
pub invariants: &'fhir [Expr<'fhir>],
}
#[derive(Debug, Clone, Copy)]
pub enum StructKind<'fhir> {
Transparent { fields: &'fhir [FieldDef<'fhir>] },
Opaque,
}
#[derive(Debug, Clone, Copy)]
pub struct FieldDef<'fhir> {
pub ty: Ty<'fhir>,
pub lifted: bool,
}
#[derive(Debug)]
pub struct EnumDef<'fhir> {
pub refined_by: &'fhir RefinedBy<'fhir>,
pub params: &'fhir [RefineParam<'fhir>],
pub variants: &'fhir [VariantDef<'fhir>],
pub invariants: &'fhir [Expr<'fhir>],
}
#[derive(Debug, Clone, Copy)]
pub struct VariantDef<'fhir> {
pub def_id: LocalDefId,
pub params: &'fhir [RefineParam<'fhir>],
pub fields: &'fhir [FieldDef<'fhir>],
pub ret: VariantRet<'fhir>,
pub span: Span,
pub lifted: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct VariantRet<'fhir> {
pub enum_id: DefId,
pub idx: Expr<'fhir>,
}
#[derive(Clone, Copy)]
pub struct FnDecl<'fhir> {
pub requires: &'fhir [Requires<'fhir>],
pub inputs: &'fhir [Ty<'fhir>],
pub output: FnOutput<'fhir>,
pub span: Span,
pub lifted: bool,
}
#[derive(Clone, Copy)]
pub struct Requires<'fhir> {
pub params: &'fhir [RefineParam<'fhir>],
pub pred: Expr<'fhir>,
}
#[derive(Clone, Copy)]
pub struct FnSig<'fhir> {
pub header: FnHeader,
pub qualifiers: &'fhir [Ident],
pub decl: &'fhir FnDecl<'fhir>,
}
#[derive(Clone, Copy)]
pub struct FnOutput<'fhir> {
pub params: &'fhir [RefineParam<'fhir>],
pub ret: Ty<'fhir>,
pub ensures: &'fhir [Ensures<'fhir>],
}
#[derive(Clone, Copy)]
pub enum Ensures<'fhir> {
Type(PathExpr<'fhir>, Ty<'fhir>),
Pred(Expr<'fhir>),
}
#[derive(Clone, Copy)]
pub struct Ty<'fhir> {
pub kind: TyKind<'fhir>,
pub span: Span,
}
#[derive(Clone, Copy)]
pub enum TyKind<'fhir> {
BaseTy(BaseTy<'fhir>),
Indexed(BaseTy<'fhir>, Expr<'fhir>),
Exists(&'fhir [RefineParam<'fhir>], &'fhir Ty<'fhir>),
Constr(Expr<'fhir>, &'fhir Ty<'fhir>),
StrgRef(Lifetime, &'fhir PathExpr<'fhir>, &'fhir Ty<'fhir>),
Ref(Lifetime, MutTy<'fhir>),
BareFn(&'fhir BareFnTy<'fhir>),
Tuple(&'fhir [Ty<'fhir>]),
Array(&'fhir Ty<'fhir>, ConstArg),
RawPtr(&'fhir Ty<'fhir>, Mutability),
OpaqueDef(&'fhir OpaqueTy<'fhir>),
TraitObject(&'fhir [PolyTraitRef<'fhir>], Lifetime, TraitObjectSyntax),
Never,
Infer,
}
pub struct BareFnTy<'fhir> {
pub safety: Safety,
pub abi: abi::Abi,
pub generic_params: &'fhir [GenericParam<'fhir>],
pub decl: &'fhir FnDecl<'fhir>,
pub param_names: &'fhir [Ident],
}
#[derive(Clone, Copy)]
pub struct MutTy<'fhir> {
pub ty: &'fhir Ty<'fhir>,
pub mutbl: Mutability,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Lifetime {
Hole(FhirId),
Resolved(ResolvedArg),
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum FluxLocalDefId {
Flux(Symbol),
Rust(LocalDefId),
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Encodable, Decodable)]
pub enum FluxOwnerId {
Flux(Symbol),
Rust(OwnerId),
}
impl FluxOwnerId {
pub fn def_id(self) -> Option<LocalDefId> {
match self {
FluxOwnerId::Flux(_) => None,
FluxOwnerId::Rust(owner_id) => Some(owner_id.def_id),
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, Encodable, Decodable)]
pub struct FhirId {
pub owner: FluxOwnerId,
pub local_id: ItemLocalId,
}
newtype_index! {
#[encodable]
pub struct ItemLocalId {}
}
#[derive(Clone, Copy)]
pub struct BaseTy<'fhir> {
pub kind: BaseTyKind<'fhir>,
pub fhir_id: FhirId,
pub span: Span,
}
impl<'fhir> BaseTy<'fhir> {
pub fn from_qpath(qpath: QPath<'fhir>, fhir_id: FhirId) -> Self {
let span = qpath.span();
Self { kind: BaseTyKind::Path(qpath), fhir_id, span }
}
fn as_path(&self) -> Option<Path<'fhir>> {
match self.kind {
BaseTyKind::Path(QPath::Resolved(None, path)) => Some(path),
_ => None,
}
}
}
#[derive(Clone, Copy)]
pub enum BaseTyKind<'fhir> {
Path(QPath<'fhir>),
Slice(&'fhir Ty<'fhir>),
}
#[derive(Clone, Copy)]
pub enum QPath<'fhir> {
Resolved(Option<&'fhir Ty<'fhir>>, Path<'fhir>),
TypeRelative(&'fhir Ty<'fhir>, &'fhir PathSegment<'fhir>),
}
#[derive(Clone, Copy)]
pub struct Path<'fhir> {
pub res: Res,
pub segments: &'fhir [PathSegment<'fhir>],
pub refine: &'fhir [Expr<'fhir>],
pub span: Span,
}
impl<'fhir> Path<'fhir> {
pub fn last_segment(&self) -> &'fhir PathSegment<'fhir> {
self.segments.last().unwrap()
}
}
#[derive(Clone, Copy)]
pub struct PathSegment<'fhir> {
pub ident: Ident,
pub res: Res,
pub args: &'fhir [GenericArg<'fhir>],
pub constraints: &'fhir [AssocItemConstraint<'fhir>],
}
#[derive(Clone, Copy)]
pub struct AssocItemConstraint<'fhir> {
pub ident: Ident,
pub kind: AssocItemConstraintKind<'fhir>,
}
#[derive(Clone, Copy)]
pub enum AssocItemConstraintKind<'fhir> {
Equality { term: Ty<'fhir> },
}
#[derive(Clone, Copy)]
pub enum GenericArg<'fhir> {
Lifetime(Lifetime),
Type(&'fhir Ty<'fhir>),
Const(ConstArg),
}
impl<'fhir> GenericArg<'fhir> {
pub fn expect_type(&self) -> &'fhir Ty<'fhir> {
if let GenericArg::Type(ty) = self {
ty
} else {
bug!("expected `GenericArg::Type`")
}
}
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct ConstArg {
pub kind: ConstArgKind,
pub span: Span,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum ConstArgKind {
Lit(usize),
Param(DefId),
Infer,
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Res {
Def(DefKind, DefId),
PrimTy(PrimTy),
SelfTyAlias { alias_to: DefId, is_trait_impl: bool },
SelfTyParam { trait_: DefId },
Err,
}
#[derive(Copy, Clone, Debug)]
pub struct PartialRes {
base_res: Res,
unresolved_segments: usize,
}
impl PartialRes {
pub fn new(base_res: Res) -> Self {
Self { base_res, unresolved_segments: 0 }
}
pub fn with_unresolved_segments(base_res: Res, unresolved_segments: usize) -> Self {
Self { base_res, unresolved_segments }
}
#[inline]
pub fn base_res(&self) -> Res {
self.base_res
}
pub fn unresolved_segments(&self) -> usize {
self.unresolved_segments
}
#[inline]
pub fn full_res(&self) -> Option<Res> {
(self.unresolved_segments == 0).then_some(self.base_res)
}
#[inline]
pub fn expect_full_res(&self) -> Res {
self.full_res().unwrap_or_else(|| bug!("expected full res"))
}
pub fn is_box(&self, tcx: TyCtxt) -> bool {
self.full_res().map_or(false, |res| res.is_box(tcx))
}
}
#[derive(Debug, Clone, Copy)]
pub struct RefineParam<'fhir> {
pub id: ParamId,
pub name: Symbol,
pub span: Span,
pub sort: Sort<'fhir>,
pub kind: ParamKind,
pub fhir_id: FhirId,
}
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum ParamKind {
Explicit(Option<ParamMode>),
At,
Pound,
Colon,
Loc,
Error,
}
impl ParamKind {
pub fn is_loc(&self) -> bool {
matches!(self, ParamKind::Loc)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum InferMode {
EVar,
KVar,
}
impl InferMode {
pub fn from_param_kind(kind: ParamKind) -> InferMode {
if let ParamKind::Explicit(Some(ParamMode::Horn)) = kind {
InferMode::KVar
} else {
InferMode::EVar
}
}
pub fn prefix_str(self) -> &'static str {
match self {
InferMode::EVar => "?",
InferMode::KVar => "$",
}
}
}
#[derive(Clone, Copy)]
pub enum PrimSort {
Int,
Bool,
Real,
Set,
Map,
}
impl PrimSort {
pub fn name_str(self) -> &'static str {
match self {
PrimSort::Int => "int",
PrimSort::Bool => "bool",
PrimSort::Real => "real",
PrimSort::Set => "Set",
PrimSort::Map => "Map",
}
}
pub fn generics(self) -> usize {
match self {
PrimSort::Int => 0,
PrimSort::Bool => 0,
PrimSort::Real => 0,
PrimSort::Set => 1,
PrimSort::Map => 2,
}
}
}
#[derive(Clone, Copy)]
pub enum SortRes {
PrimSort(PrimSort),
User { name: Symbol },
SortParam(usize),
TyParam(DefId),
SelfParam {
trait_id: DefId,
},
SelfAlias {
alias_to: DefId,
},
SelfParamAssoc { trait_id: DefId, ident: Ident },
Adt(DefId),
}
#[derive(Clone, Copy)]
pub enum Sort<'fhir> {
Path(SortPath<'fhir>),
Loc,
BitVec(usize),
Func(PolyFuncSort<'fhir>),
Infer,
}
#[derive(Clone, Copy)]
pub struct SortPath<'fhir> {
pub res: SortRes,
pub segments: &'fhir [Ident],
pub args: &'fhir [Sort<'fhir>],
}
#[derive(Clone, Copy)]
pub struct FuncSort<'fhir> {
pub inputs_and_output: &'fhir [Sort<'fhir>],
}
#[derive(Clone, Copy)]
pub struct PolyFuncSort<'fhir> {
pub params: usize,
pub fsort: FuncSort<'fhir>,
}
impl<'fhir> PolyFuncSort<'fhir> {
pub fn new(params: usize, inputs_and_output: &'fhir [Sort]) -> Self {
let fsort = FuncSort { inputs_and_output };
Self { params, fsort }
}
}
#[derive(Clone, Copy)]
pub struct AliasReft<'fhir> {
pub qself: &'fhir Ty<'fhir>,
pub path: Path<'fhir>,
pub name: Symbol,
}
#[derive(Debug, Clone, Copy)]
pub struct FieldExpr<'fhir> {
pub ident: Ident,
pub expr: Expr<'fhir>,
pub fhir_id: FhirId,
pub span: Span,
}
#[derive(Debug, Clone, Copy)]
pub struct Spread<'fhir> {
pub expr: Expr<'fhir>,
pub span: Span,
pub fhir_id: FhirId,
}
#[derive(Clone, Copy)]
pub struct Expr<'fhir> {
pub kind: ExprKind<'fhir>,
pub fhir_id: FhirId,
pub span: Span,
}
#[derive(Clone, Copy)]
pub enum ExprKind<'fhir> {
Var(PathExpr<'fhir>, Option<ParamKind>),
Dot(PathExpr<'fhir>, Ident),
Literal(Lit),
BinaryOp(BinOp, &'fhir Expr<'fhir>, &'fhir Expr<'fhir>),
UnaryOp(UnOp, &'fhir Expr<'fhir>),
App(PathExpr<'fhir>, &'fhir [Expr<'fhir>]),
Alias(AliasReft<'fhir>, &'fhir [Expr<'fhir>]),
IfThenElse(&'fhir Expr<'fhir>, &'fhir Expr<'fhir>, &'fhir Expr<'fhir>),
Abs(&'fhir [RefineParam<'fhir>], &'fhir Expr<'fhir>),
Record(&'fhir [Expr<'fhir>]),
Constructor(Option<PathExpr<'fhir>>, &'fhir [FieldExpr<'fhir>], Option<&'fhir Spread<'fhir>>),
}
impl Expr<'_> {
pub fn is_colon_param(&self) -> Option<ParamId> {
if let ExprKind::Var(path, Some(ParamKind::Colon)) = &self.kind
&& let ExprRes::Param(kind, id) = path.res
{
debug_assert_eq!(kind, ParamKind::Colon);
Some(id)
} else {
None
}
}
}
#[derive(Clone, Copy)]
pub enum Lit {
Int(i128),
Real(i128),
Bool(bool),
Str(Symbol),
Char(char),
}
#[derive(Clone, Copy, Debug)]
pub enum ExprRes<Id = ParamId> {
Param(ParamKind, Id),
Const(DefId),
Ctor(DefId),
ConstGeneric(DefId),
NumConst(i128),
GlobalFunc(SpecFuncKind, Symbol),
}
impl<Id> ExprRes<Id> {
pub fn map_param_id<R>(self, f: impl FnOnce(Id) -> R) -> ExprRes<R> {
match self {
ExprRes::Param(kind, param_id) => ExprRes::Param(kind, f(param_id)),
ExprRes::Const(def_id) => ExprRes::Const(def_id),
ExprRes::NumConst(val) => ExprRes::NumConst(val),
ExprRes::GlobalFunc(kind, name) => ExprRes::GlobalFunc(kind, name),
ExprRes::ConstGeneric(def_id) => ExprRes::ConstGeneric(def_id),
ExprRes::Ctor(def_id) => ExprRes::Ctor(def_id),
}
}
pub fn expect_param(self) -> (ParamKind, Id) {
if let ExprRes::Param(kind, id) = self {
(kind, id)
} else {
bug!("expected param")
}
}
}
#[derive(Clone, Copy)]
pub struct PathExpr<'fhir> {
pub segments: &'fhir [Ident],
pub res: ExprRes,
pub fhir_id: FhirId,
pub span: Span,
}
newtype_index! {
#[debug_format = "a{}"]
pub struct ParamId {}
}
impl PolyTraitRef<'_> {
pub fn trait_def_id(&self) -> DefId {
let path = &self.trait_ref;
if let Res::Def(DefKind::Trait, did) = path.res {
did
} else {
span_bug!(path.span, "unexpected resolution {:?}", path.res);
}
}
}
impl From<FluxOwnerId> for FluxLocalDefId {
fn from(flux_id: FluxOwnerId) -> Self {
match flux_id {
FluxOwnerId::Flux(sym) => FluxLocalDefId::Flux(sym),
FluxOwnerId::Rust(owner_id) => FluxLocalDefId::Rust(owner_id.def_id),
}
}
}
impl From<LocalDefId> for FluxLocalDefId {
fn from(def_id: LocalDefId) -> Self {
FluxLocalDefId::Rust(def_id)
}
}
impl From<OwnerId> for FluxOwnerId {
fn from(owner_id: OwnerId) -> Self {
FluxOwnerId::Rust(owner_id)
}
}
impl<'fhir> Ty<'fhir> {
pub fn as_path(&self) -> Option<Path<'fhir>> {
match &self.kind {
TyKind::BaseTy(bty) => bty.as_path(),
_ => None,
}
}
}
impl Res {
pub fn descr(&self) -> &'static str {
match self {
Res::PrimTy(_) => "builtin type",
Res::Def(kind, def_id) => kind.descr(*def_id),
Res::SelfTyAlias { .. } | Res::SelfTyParam { .. } => "self type",
Res::Err => "unresolved item",
}
}
pub fn is_box(&self, tcx: TyCtxt) -> bool {
if let Res::Def(DefKind::Struct, def_id) = self {
tcx.adt_def(def_id).is_box()
} else {
false
}
}
}
impl<Id> TryFrom<rustc_hir::def::Res<Id>> for Res {
type Error = ();
fn try_from(res: rustc_hir::def::Res<Id>) -> Result<Self, Self::Error> {
match res {
rustc_hir::def::Res::Def(kind, did) => Ok(Res::Def(kind, did)),
rustc_hir::def::Res::PrimTy(prim_ty) => Ok(Res::PrimTy(prim_ty)),
rustc_hir::def::Res::SelfTyAlias { alias_to, forbid_generic: false, is_trait_impl } => {
Ok(Res::SelfTyAlias { alias_to, is_trait_impl })
}
rustc_hir::def::Res::SelfTyParam { trait_ } => Ok(Res::SelfTyParam { trait_ }),
rustc_hir::def::Res::Err => Ok(Res::Err),
_ => Err(()),
}
}
}
impl QPath<'_> {
pub fn span(&self) -> Span {
match self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, assoc) => qself.span.to(assoc.ident.span),
}
}
}
impl Lit {
pub const TRUE: Lit = Lit::Bool(true);
}
#[derive(Clone, Debug)]
pub struct RefinedBy<'fhir> {
pub sort_params: FxIndexSet<DefId>,
pub fields: FxIndexMap<Symbol, Sort<'fhir>>,
}
#[derive(Debug)]
pub struct SpecFunc<'fhir> {
pub name: Symbol,
pub params: usize,
pub args: &'fhir [RefineParam<'fhir>],
pub sort: Sort<'fhir>,
pub body: Option<Expr<'fhir>>,
}
#[derive(Debug, Clone, Copy, TyEncodable, TyDecodable, PartialEq, Eq, Hash)]
pub enum SpecFuncKind {
Thy(Symbol),
Uif,
Def,
}
impl<'fhir> Generics<'fhir> {
pub fn get_param(&self, def_id: LocalDefId) -> &'fhir GenericParam<'fhir> {
self.params
.iter()
.find(|p| p.def_id.local_id() == def_id)
.unwrap()
}
}
impl<'fhir> RefinedBy<'fhir> {
pub fn new(fields: FxIndexMap<Symbol, Sort<'fhir>>, sort_params: FxIndexSet<DefId>) -> Self {
RefinedBy { sort_params, fields }
}
pub fn trivial() -> Self {
RefinedBy { sort_params: Default::default(), fields: Default::default() }
}
}
impl<'fhir> From<PolyFuncSort<'fhir>> for Sort<'fhir> {
fn from(fsort: PolyFuncSort<'fhir>) -> Self {
Self::Func(fsort)
}
}
impl FuncSort<'_> {
pub fn inputs(&self) -> &[Sort] {
&self.inputs_and_output[..self.inputs_and_output.len() - 1]
}
pub fn output(&self) -> &Sort {
&self.inputs_and_output[self.inputs_and_output.len() - 1]
}
}
impl rustc_errors::IntoDiagArg for Ty<'_> {
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
}
}
impl rustc_errors::IntoDiagArg for Path<'_> {
fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
}
}
impl StructDef<'_> {
pub fn is_opaque(&self) -> bool {
matches!(self.kind, StructKind::Opaque)
}
}
impl fmt::Debug for FnSig<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.decl)
}
}
impl fmt::Debug for FnDecl<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.requires.is_empty() {
write!(f, "[{:?}] ", self.requires.iter().format(", "))?;
}
write!(f, "fn({:?}) -> {:?}", self.inputs.iter().format(", "), self.output)
}
}
impl fmt::Debug for FnOutput<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.params.is_empty() {
write!(
f,
"exists<{}> ",
self.params.iter().format_with(", ", |param, f| {
f(&format_args!("{}: {:?}", param.name, param.sort))
})
)?;
}
write!(f, "{:?}", self.ret)?;
if !self.ensures.is_empty() {
write!(f, "; [{:?}]", self.ensures.iter().format(", "))?;
}
Ok(())
}
}
impl fmt::Debug for Requires<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.params.is_empty() {
write!(
f,
"forall {}.",
self.params.iter().format_with(",", |param, f| {
f(&format_args!("{}:{:?}", param.name, param.sort))
})
)?;
}
write!(f, "{:?}", self.pred)
}
}
impl fmt::Debug for Ensures<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Ensures::Type(loc, ty) => write!(f, "{loc:?}: {ty:?}"),
Ensures::Pred(e) => write!(f, "{e:?}"),
}
}
}
impl fmt::Debug for Ty<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
TyKind::BaseTy(bty) => write!(f, "{bty:?}"),
TyKind::Indexed(bty, idx) => write!(f, "{bty:?}[{idx:?}]"),
TyKind::Exists(params, ty) => {
write!(f, "{{")?;
write!(
f,
"{}",
params.iter().format_with(",", |param, f| {
f(&format_args!("{}:{:?}", param.name, param.sort))
})
)?;
if let TyKind::Constr(pred, ty) = &ty.kind {
write!(f, ". {ty:?} | {pred:?}}}")
} else {
write!(f, ". {ty:?}}}")
}
}
TyKind::StrgRef(_lft, loc, ty) => write!(f, "&strg <{loc:?}: {ty:?}>"),
TyKind::Ref(_lft, mut_ty) => {
write!(f, "&{}{:?}", mut_ty.mutbl.prefix_str(), mut_ty.ty)
}
TyKind::BareFn(bare_fn_ty) => {
write!(f, "{bare_fn_ty:?}")
}
TyKind::Tuple(tys) => write!(f, "({:?})", tys.iter().format(", ")),
TyKind::Array(ty, len) => write!(f, "[{ty:?}; {len:?}]"),
TyKind::Never => write!(f, "!"),
TyKind::Constr(pred, ty) => write!(f, "{{{ty:?} | {pred:?}}}"),
TyKind::RawPtr(ty, Mutability::Not) => write!(f, "*const {ty:?}"),
TyKind::RawPtr(ty, Mutability::Mut) => write!(f, "*mut {ty:?}"),
TyKind::Infer => write!(f, "_"),
TyKind::OpaqueDef(opaque_ty) => {
write!(f, "impl trait <def_id = {:?}>", opaque_ty.def_id.resolved_id(),)
}
TyKind::TraitObject(poly_traits, _lft, _syntax) => {
write!(f, "dyn {poly_traits:?}")
}
}
}
}
impl fmt::Debug for BareFnTy<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.generic_params.is_empty() {
write!(
f,
"for<{}>",
self.generic_params
.iter()
.map(|param| param.name.ident())
.format(",")
)?;
}
write!(f, "{:?}", self.decl)
}
}
impl fmt::Debug for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Lifetime::Hole(_) => write!(f, "'_"),
Lifetime::Resolved(lft) => write!(f, "{lft:?}"),
}
}
}
impl fmt::Debug for ConstArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.kind)
}
}
impl fmt::Debug for ConstArgKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConstArgKind::Lit(n) => write!(f, "{n}"),
ConstArgKind::Param(p) => write!(f, "{:?}", p),
ConstArgKind::Infer => write!(f, "_"),
}
}
}
impl fmt::Debug for BaseTy<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
BaseTyKind::Path(qpath) => write!(f, "{qpath:?}"),
BaseTyKind::Slice(ty) => write!(f, "[{ty:?}]"),
}
}
}
impl fmt::Debug for QPath<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
QPath::Resolved(_, path) => write!(f, "{path:?}"),
QPath::TypeRelative(qself, assoc) => write!(f, "<{qself:?}>::{assoc:?}"),
}
}
}
impl fmt::Debug for Path<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.segments.iter().format("::"))?;
if !self.refine.is_empty() {
write!(f, "({:?})", self.refine.iter().format(", "))?;
}
Ok(())
}
}
impl fmt::Debug for PathSegment<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.ident)?;
let args: Vec<_> = self
.args
.iter()
.map(|a| a as &dyn std::fmt::Debug)
.chain(self.constraints.iter().map(|b| b as &dyn std::fmt::Debug))
.collect();
if !args.is_empty() {
write!(f, "<{:?}>", args.iter().format(", "))?;
}
Ok(())
}
}
impl fmt::Debug for GenericArg<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GenericArg::Type(ty) => write!(f, "{ty:?}"),
GenericArg::Lifetime(lft) => write!(f, "{lft:?}"),
GenericArg::Const(cst) => write!(f, "{cst:?}"),
}
}
}
impl fmt::Debug for AssocItemConstraint<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
AssocItemConstraintKind::Equality { term } => {
write!(f, "{:?} = {:?}", self.ident, term)
}
}
}
}
impl fmt::Debug for AliasReft<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{:?} as {:?}>::{}", self.qself, self.path, self.name)
}
}
impl fmt::Debug for Expr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
ExprKind::Var(x, ..) => write!(f, "{x:?}"),
ExprKind::BinaryOp(op, e1, e2) => write!(f, "({e1:?} {op:?} {e2:?})"),
ExprKind::UnaryOp(op, e) => write!(f, "{op:?}{e:?}"),
ExprKind::Literal(lit) => write!(f, "{lit:?}"),
ExprKind::App(uf, es) => write!(f, "{uf:?}({:?})", es.iter().format(", ")),
ExprKind::Alias(alias, refine_args) => {
write!(f, "{alias:?}({:?})", refine_args.iter().format(", "))
}
ExprKind::IfThenElse(p, e1, e2) => {
write!(f, "(if {p:?} {{ {e1:?} }} else {{ {e2:?} }})")
}
ExprKind::Dot(var, fld) => write!(f, "{var:?}.{fld}"),
ExprKind::Abs(params, body) => {
write!(
f,
"|{}| {body:?}",
params.iter().format_with(", ", |param, f| {
f(&format_args!("{}: {:?}", param.name, param.sort))
})
)
}
ExprKind::Record(flds) => {
write!(f, "{{ {:?} }}", flds.iter().format(", "))
}
ExprKind::Constructor(path, exprs, spread) => {
if let Some(path) = path
&& let Some(s) = spread
{
write!(f, "{:?} {{ {:?}, ..{:?} }}", path, exprs.iter().format(", "), s)
} else if let Some(path) = path {
write!(f, "{:?} {{ {:?} }}", path, exprs.iter().format(", "))
} else if let Some(s) = spread {
write!(f, "{{ {:?} ..{:?} }}", exprs.iter().format(", "), s)
} else {
write!(f, "{{ {:?} }}", exprs.iter().format(", "))
}
}
}
}
}
impl fmt::Debug for PathExpr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.segments.iter().format("::"))
}
}
impl fmt::Debug for Lit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Lit::Int(i) => write!(f, "{i}"),
Lit::Real(r) => write!(f, "{r}real"),
Lit::Bool(b) => write!(f, "{b}"),
Lit::Str(s) => write!(f, "\"{s:?}\""),
Lit::Char(c) => write!(f, "\'{c}\'"),
}
}
}
impl fmt::Debug for Sort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Sort::Path(path) => write!(f, "{path:?}"),
Sort::BitVec(w) => write!(f, "bitvec({w})"),
Sort::Loc => write!(f, "loc"),
Sort::Func(fsort) => write!(f, "{fsort:?}"),
Sort::Infer => write!(f, "_"),
}
}
}
impl fmt::Debug for SortPath<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.res)?;
if !self.args.is_empty() {
write!(f, "<{:?}>", self.args.iter().format(", "))?;
}
Ok(())
}
}
impl fmt::Debug for SortRes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SortRes::PrimSort(PrimSort::Bool) => write!(f, "bool"),
SortRes::PrimSort(PrimSort::Int) => write!(f, "int"),
SortRes::PrimSort(PrimSort::Real) => write!(f, "real"),
SortRes::PrimSort(PrimSort::Set) => write!(f, "Set"),
SortRes::PrimSort(PrimSort::Map) => write!(f, "Map"),
SortRes::SortParam(n) => write!(f, "@{}", n),
SortRes::TyParam(def_id) => write!(f, "{}::sort", def_id_to_string(*def_id)),
SortRes::SelfParam { trait_id } => {
write!(f, "{}::Self::sort", def_id_to_string(*trait_id))
}
SortRes::SelfAlias { alias_to } => {
write!(f, "{}::Self::sort", def_id_to_string(*alias_to))
}
SortRes::SelfParamAssoc { ident: assoc, .. } => {
write!(f, "Self::{assoc}")
}
SortRes::User { name } => write!(f, "{name}"),
SortRes::Adt(def_id) => write!(f, "{}::sort", def_id_to_string(*def_id)),
}
}
}
impl fmt::Debug for PolyFuncSort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.params > 0 {
write!(f, "for<{}>{:?}", self.params, self.fsort)
} else {
write!(f, "{:?}", self.fsort)
}
}
}
impl fmt::Debug for FuncSort<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.inputs() {
[input] => {
write!(f, "{:?} -> {:?}", input, self.output())
}
inputs => {
write!(f, "({:?}) -> {:?}", inputs.iter().format(", "), self.output())
}
}
}
}