From 30f07f2d52a6df68ae8785c533f338a25581dc4d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 11 Jun 2024 08:57:37 +0200 Subject: [PATCH 1/6] refactor: feature gate all implementations with feat. `full` This PR adds a (default) feature `full` for the `hax-frontend-exporter` crate. With this feature disabled, the crate turns into a mostly type-only crate. The crate depends on rustc and drive `sinto` only with `full` enabled. --- Cargo.lock | 1 + frontend/exporter/Cargo.toml | 16 +- frontend/exporter/adt-into/src/lib.rs | 1 + frontend/exporter/src/body.rs | 167 ++-- frontend/exporter/src/constant_utils.rs | 681 ++++++++------- frontend/exporter/src/index_vec.rs | 9 +- frontend/exporter/src/lib.rs | 65 +- frontend/exporter/src/prelude.rs | 12 +- frontend/exporter/src/sinto.rs | 11 + frontend/exporter/src/state.rs | 2 +- frontend/exporter/src/traits.rs | 810 +++++++++--------- frontend/exporter/src/types/copied.rs | 63 +- frontend/exporter/src/types/def_id.rs | 5 +- frontend/exporter/src/types/index.rs | 1 - frontend/exporter/src/types/mir.rs | 14 + frontend/exporter/src/types/mod.rs | 2 + .../exporter/src/types/new/item_attributes.rs | 2 + .../exporter/src/types/new/predicate_id.rs | 94 +- .../src/types/new/typed_constant_kind.rs | 1 + frontend/exporter/src/types/replaced.rs | 29 +- frontend/exporter/src/types/todo.rs | 1 - 21 files changed, 1081 insertions(+), 906 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f332a8ad..e1d8e2dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,6 +534,7 @@ dependencies = [ name = "hax-frontend-exporter" version = "0.1.0-pre.1" dependencies = [ + "cfg-if", "extension-traits", "hax-adt-into", "hax-frontend-exporter-options", diff --git a/frontend/exporter/Cargo.toml b/frontend/exporter/Cargo.toml index 3ac731416..b8a350aa7 100644 --- a/frontend/exporter/Cargo.toml +++ b/frontend/exporter/Cargo.toml @@ -13,13 +13,19 @@ description = "Provides mirrors of the algebraic data types used in the Rust com rustc_private=true [dependencies] -hax-adt-into.workspace = true serde.workspace = true serde_json.workspace = true schemars.workspace = true -itertools.workspace = true hax-frontend-exporter-options.workspace = true -tracing.workspace = true +hax-adt-into.workspace = true paste = "1.0.11" -extension-traits = "1.0.1" -lazy_static = "1.4.0" + +tracing = { workspace = true, optional = true } +itertools = { workspace = true, optional = true } +extension-traits = { version = "1.0.1", optional = true } +lazy_static = { version = "1.4.0", optional = true } +cfg-if = "1.0.0" + +[features] +default = ["full"] +full = ["dep:tracing", "dep:itertools", "dep:extension-traits", "dep:lazy_static"] diff --git a/frontend/exporter/adt-into/src/lib.rs b/frontend/exporter/adt-into/src/lib.rs index 28628646f..8cbe7c314 100644 --- a/frontend/exporter/adt-into/src/lib.rs +++ b/frontend/exporter/adt-into/src/lib.rs @@ -384,6 +384,7 @@ pub fn adt_into(input: proc_macro::TokenStream) -> proc_macro::TokenStream { }; quote! { + #[cfg(feature = "full")] const _ : () = { use #from as FROM_TYPE; use #to as TO_TYPE; diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index 89cb57c89..388281d18 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -1,99 +1,110 @@ -use crate::prelude::*; +#[cfg(feature = "full")] +mod module { + use crate::prelude::*; -pub use rustc_hir::{ - def_id::{DefId as RDefId, LocalDefId as RLocalDefId}, - hir_id::OwnerId as ROwnerId, -}; + pub use rustc_hir::{ + def_id::{DefId as RDefId, LocalDefId as RLocalDefId}, + hir_id::OwnerId as ROwnerId, + }; -pub fn get_thir<'tcx, S: UnderOwnerState<'tcx>>( - did: RLocalDefId, - s: &S, -) -> ( - Rc>, - rustc_middle::thir::ExprId, -) { - let base = s.base(); - let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); - base.cached_thirs.get(&did).unwrap_or_else(msg).clone() -} + pub fn get_thir<'tcx, S: UnderOwnerState<'tcx>>( + did: RLocalDefId, + s: &S, + ) -> ( + Rc>, + rustc_middle::thir::ExprId, + ) { + let base = s.base(); + let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); + base.cached_thirs.get(&did).unwrap_or_else(msg).clone() + } -pub trait IsBody: Sized + Clone { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self; -} + pub trait IsBody: Sized + Clone { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self; + } -pub fn make_fn_def<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( - fn_sig: &rustc_hir::FnSig, - body_id: &rustc_hir::BodyId, - s: &S, -) -> FnDef { - let hir_id = body_id.hir_id; - let ldid = hir_id.clone().owner.def_id; + pub fn make_fn_def<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( + fn_sig: &rustc_hir::FnSig, + body_id: &rustc_hir::BodyId, + s: &S, + ) -> FnDef { + let hir_id = body_id.hir_id; + let ldid = hir_id.clone().owner.def_id; - let (thir, expr_entrypoint) = get_thir(ldid, s); - let s = &with_owner_id(s.base(), thir.clone(), (), ldid.to_def_id()); - FnDef { - params: thir.params.raw.sinto(s), - ret: thir.exprs[expr_entrypoint].ty.sinto(s), - body: Body::body(ldid, s), - sig_span: fn_sig.span.sinto(s), - header: fn_sig.header.sinto(s), + let (thir, expr_entrypoint) = get_thir(ldid, s); + let s = &with_owner_id(s.base(), thir.clone(), (), ldid.to_def_id()); + FnDef { + params: thir.params.raw.sinto(s), + ret: thir.exprs[expr_entrypoint].ty.sinto(s), + body: Body::body(ldid, s), + sig_span: fn_sig.span.sinto(s), + header: fn_sig.header.sinto(s), + } } -} -pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( - id: rustc_hir::BodyId, - s: &S, -) -> Body { - // **Important:** - // We need a local id here, and we get it from the owner id, which must - // be local. It is safe to do so, because if we have access to HIR objects, - // it necessarily means we are exploring a local item (we don't have - // access to the HIR of external objects, only their MIR). - Body::body(s.base().tcx.hir().body_owner_def_id(id), s) -} + pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( + id: rustc_hir::BodyId, + s: &S, + ) -> Body { + // **Important:** + // We need a local id here, and we get it from the owner id, which must + // be local. It is safe to do so, because if we have access to HIR objects, + // it necessarily means we are exploring a local item (we don't have + // access to the HIR of external objects, only their MIR). + Body::body(s.base().tcx.hir().body_owner_def_id(id), s) + } -mod implementations { - use super::*; - impl IsBody for () { - fn body<'tcx, S: UnderOwnerState<'tcx>>(_did: RLocalDefId, _s: &S) -> Self { - () + mod implementations { + use super::*; + impl IsBody for () { + fn body<'tcx, S: UnderOwnerState<'tcx>>(_did: RLocalDefId, _s: &S) -> Self { + () + } } - } - impl IsBody for ThirBody { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - let (thir, expr) = get_thir(did, s); - if *CORE_EXTRACTION_MODE { - let expr = &thir.exprs[expr.clone()]; - Decorated { - contents: Box::new(ExprKind::Tuple { fields: vec![] }), - hir_id: None, - attributes: vec![], - ty: expr.ty.sinto(s), - span: expr.span.sinto(s), + impl IsBody for ThirBody { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + let (thir, expr) = get_thir(did, s); + if *CORE_EXTRACTION_MODE { + let expr = &thir.exprs[expr.clone()]; + Decorated { + contents: Box::new(ExprKind::Tuple { fields: vec![] }), + hir_id: None, + attributes: vec![], + ty: expr.ty.sinto(s), + span: expr.span.sinto(s), + } + } else { + expr.sinto(&with_owner_id(s.base(), thir, (), did.to_def_id())) } - } else { - expr.sinto(&with_owner_id(s.base(), thir, (), did.to_def_id())) } } - } - impl IsBody for (A, B) { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - (A::body(did, s), B::body(did, s)) + impl IsBody for (A, B) { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + (A::body(did, s), B::body(did, s)) + } + } + + impl IsBody for MirBody { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + let (thir, _) = get_thir(did, s); + let mir = Rc::new(s.base().tcx.mir_built(did).borrow().clone()); + mir.sinto(&with_owner_id(s.base(), thir, mir.clone(), did.to_def_id())) + } } } - impl IsBody for MirBody { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - let (thir, _) = get_thir(did, s); - let mir = Rc::new(s.base().tcx.mir_built(did).borrow().clone()); - mir.sinto(&with_owner_id(s.base(), thir, mir.clone(), did.to_def_id())) + impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto for rustc_hir::BodyId { + fn sinto(&self, s: &S) -> Body { + body_from_id::(self.clone(), s) } } } -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto for rustc_hir::BodyId { - fn sinto(&self, s: &S) -> Body { - body_from_id::(self.clone(), s) - } +#[cfg(not(feature = "full"))] +mod module { + pub trait IsBody: Sized + Clone {} + impl IsBody for T {} } + +pub use module::*; diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 6c99bb3d9..a743f7291 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use rustc_middle::{mir, ty}; #[derive( Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, @@ -100,132 +99,137 @@ pub struct ConstantFieldExpr { /// two construct to one same `ConstantExpr` type. pub type ConstantExpr = Decorated; -impl From for FieldExpr { - fn from(c: ConstantFieldExpr) -> FieldExpr { - FieldExpr { - value: c.value.into(), - field: c.field, +#[cfg(feature = "full")] +mod full { + use super::*; + use rustc_middle::{mir, ty}; + + impl From for FieldExpr { + fn from(c: ConstantFieldExpr) -> FieldExpr { + FieldExpr { + value: c.value.into(), + field: c.field, + } } } -} -impl ConstantLiteral { - /// Rustc always represents string constants as `&[u8]`, but this - /// is not nice to consume. This associated function interpret - /// bytes as an unicode string, and as a byte string otherwise. - fn byte_str(bytes: Vec, style: StrStyle) -> Self { - match String::from_utf8(bytes.clone()) { - Ok(s) => Self::Str(s, style), - Err(_) => Self::ByteStr(bytes, style), + impl ConstantLiteral { + /// Rustc always represents string constants as `&[u8]`, but this + /// is not nice to consume. This associated function interpret + /// bytes as an unicode string, and as a byte string otherwise. + fn byte_str(bytes: Vec, style: StrStyle) -> Self { + match String::from_utf8(bytes.clone()) { + Ok(s) => Self::Str(s, style), + Err(_) => Self::ByteStr(bytes, style), + } } } -} -impl From for Expr { - fn from(c: ConstantExpr) -> Expr { - use ConstantExprKind::*; - let kind = match *c.contents { - Literal(lit) => { - use ConstantLiteral::*; - let mut neg = false; - let node = match lit { - Bool(b) => LitKind::Bool(b), - Char(c) => LitKind::Char(c), - Int(i) => { - use LitIntType::*; - match i { - ConstantInt::Uint(v, t) => LitKind::Int(v, Unsigned(t)), - ConstantInt::Int(v, t) => { - neg = v.is_negative(); - LitKind::Int(v.abs_diff(0), Signed(t)) + impl From for Expr { + fn from(c: ConstantExpr) -> Expr { + use ConstantExprKind::*; + let kind = match *c.contents { + Literal(lit) => { + use ConstantLiteral::*; + let mut neg = false; + let node = match lit { + Bool(b) => LitKind::Bool(b), + Char(c) => LitKind::Char(c), + Int(i) => { + use LitIntType::*; + match i { + ConstantInt::Uint(v, t) => LitKind::Int(v, Unsigned(t)), + ConstantInt::Int(v, t) => { + neg = v.is_negative(); + LitKind::Int(v.abs_diff(0), Signed(t)) + } } } - } - ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style), - Str(raw, str_style) => LitKind::Str(raw, str_style), - }; - let span = c.span.clone(); - let lit = Spanned { span, node }; - ExprKind::Literal { lit, neg } - } - Adt { info, fields } => ExprKind::Adt(AdtExpr { - info, - fields: fields.into_iter().map(|field| field.into()).collect(), - base: None, - user_ty: None, - }), - // TODO: propagate the generics and trait refs (see #636) - GlobalName { - id, - generics: _, - trait_refs: _, - } => ExprKind::GlobalName { id }, - Borrow(e) => ExprKind::Borrow { - borrow_kind: BorrowKind::Shared, - arg: e.into(), - }, - ConstRef { id } => ExprKind::ConstRef { id }, - Array { fields } => ExprKind::Array { - fields: fields.into_iter().map(|field| field.into()).collect(), - }, - Tuple { fields } => ExprKind::Tuple { - fields: fields.into_iter().map(|field| field.into()).collect(), - }, - kind @ (FnPtr { .. } | TraitConst { .. }) => { - // SH: I see the `Closure` kind, but it's not the same as function pointer? - ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind)) + ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style), + Str(raw, str_style) => LitKind::Str(raw, str_style), + }; + let span = c.span.clone(); + let lit = Spanned { span, node }; + ExprKind::Literal { lit, neg } + } + Adt { info, fields } => ExprKind::Adt(AdtExpr { + info, + fields: fields.into_iter().map(|field| field.into()).collect(), + base: None, + user_ty: None, + }), + // TODO: propagate the generics and trait refs (see #636) + GlobalName { + id, + generics: _, + trait_refs: _, + } => ExprKind::GlobalName { id }, + Borrow(e) => ExprKind::Borrow { + borrow_kind: BorrowKind::Shared, + arg: e.into(), + }, + ConstRef { id } => ExprKind::ConstRef { id }, + Array { fields } => ExprKind::Array { + fields: fields.into_iter().map(|field| field.into()).collect(), + }, + Tuple { fields } => ExprKind::Tuple { + fields: fields.into_iter().map(|field| field.into()).collect(), + }, + kind @ (FnPtr { .. } | TraitConst { .. }) => { + // SH: I see the `Closure` kind, but it's not the same as function pointer? + ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind)) + } + Todo(msg) => ExprKind::Todo(msg), + }; + Decorated { + contents: Box::new(kind), + ..c } - Todo(msg) => ExprKind::Todo(msg), - }; - Decorated { - contents: Box::new(kind), - ..c } } -} -pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - x: rustc_middle::ty::ScalarInt, - ty: rustc_middle::ty::Ty, -) -> ConstantLiteral { - match ty.kind() { - ty::Char => ConstantLiteral::Char( - char::try_from(x) - .s_expect(s, "scalar_int_to_constant_literal: expected a char") - .into(), - ), - ty::Bool => ConstantLiteral::Bool( - x.try_to_bool() - .s_expect(s, "scalar_int_to_constant_literal: expected a bool"), - ), - ty::Int(kind) => { - let v = x.try_to_int(x.size()).s_unwrap(s); - ConstantLiteral::Int(ConstantInt::Int(v, kind.sinto(s))) - } - ty::Uint(kind) => { - let v = x.try_to_uint(x.size()).s_unwrap(s); - ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) + pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + x: rustc_middle::ty::ScalarInt, + ty: rustc_middle::ty::Ty, + ) -> ConstantLiteral { + match ty.kind() { + ty::Char => ConstantLiteral::Char( + char::try_from(x) + .s_expect(s, "scalar_int_to_constant_literal: expected a char") + .into(), + ), + ty::Bool => ConstantLiteral::Bool( + x.try_to_bool() + .s_expect(s, "scalar_int_to_constant_literal: expected a bool"), + ), + ty::Int(kind) => { + let v = x.try_to_int(x.size()).s_unwrap(s); + ConstantLiteral::Int(ConstantInt::Int(v, kind.sinto(s))) + } + ty::Uint(kind) => { + let v = x.try_to_uint(x.size()).s_unwrap(s); + ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) + } + _ => fatal!( + s, + "scalar_int_to_constant_literal: the type {:?} is not a literal", + ty + ), } - _ => fatal!( - s, - "scalar_int_to_constant_literal: the type {:?} is not a literal", - ty - ), } -} -pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - scalar: &rustc_middle::mir::interpret::Scalar, - span: rustc_span::Span, -) -> ConstantExpr { - use rustc_middle::mir::Mutability; - let cspan = span.sinto(s); - // The documentation explicitly says not to match on a scalar. - // We match on the type and use it to convert the value. - let kind = match ty.kind() { + pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + scalar: &rustc_middle::mir::interpret::Scalar, + span: rustc_span::Span, + ) -> ConstantExpr { + use rustc_middle::mir::Mutability; + let cspan = span.sinto(s); + // The documentation explicitly says not to match on a scalar. + // We match on the type and use it to convert the value. + let kind = match ty.kind() { ty::Char | ty::Bool | ty::Int(_) | ty::Uint(_) => { let scalar_int = scalar.try_to_int().unwrap_or_else(|_| { fatal!( @@ -282,160 +286,165 @@ pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( scalar ), }; - kind.decorate(ty.sinto(s), cspan) -} + kind.decorate(ty.sinto(s), cspan) + } -/// Whether a `DefId` is a `AnonConst`. An anonymous constant is -/// generated by Rustc, hoisting every constat bits from items as -/// separate top-level items. This AnonConst mechanism is internal to -/// Rustc; we don't want to reflect that, instead we prefer inlining -/// those. `is_anon_const` is used to detect such AnonConst so that we -/// can evaluate and inline them. -pub(crate) fn is_anon_const<'tcx>( - did: rustc_span::def_id::DefId, - tcx: rustc_middle::ty::TyCtxt<'tcx>, -) -> bool { - matches!( - tcx.def_path(did).data.last().map(|x| x.data), - Some(rustc_hir::definitions::DefPathData::AnonConst) - ) -} + /// Whether a `DefId` is a `AnonConst`. An anonymous constant is + /// generated by Rustc, hoisting every constat bits from items as + /// separate top-level items. This AnonConst mechanism is internal to + /// Rustc; we don't want to reflect that, instead we prefer inlining + /// those. `is_anon_const` is used to detect such AnonConst so that we + /// can evaluate and inline them. + pub(crate) fn is_anon_const<'tcx>( + did: rustc_span::def_id::DefId, + tcx: rustc_middle::ty::TyCtxt<'tcx>, + ) -> bool { + matches!( + tcx.def_path(did).data.last().map(|x| x.data), + Some(rustc_hir::definitions::DefPathData::AnonConst) + ) + } -fn trait_const_to_constant_expr_kind<'tcx, S: BaseState<'tcx> + HasOwnerId>( - s: &S, - _const_def_id: rustc_hir::def_id::DefId, - generics: rustc_middle::ty::GenericArgsRef<'tcx>, - assoc: &rustc_middle::ty::AssocItem, -) -> ConstantExprKind { - assert!(assoc.trait_item_def_id.is_some()); - let name = assoc.name.to_string(); + fn trait_const_to_constant_expr_kind<'tcx, S: BaseState<'tcx> + HasOwnerId>( + s: &S, + _const_def_id: rustc_hir::def_id::DefId, + generics: rustc_middle::ty::GenericArgsRef<'tcx>, + assoc: &rustc_middle::ty::AssocItem, + ) -> ConstantExprKind { + assert!(assoc.trait_item_def_id.is_some()); + let name = assoc.name.to_string(); - // Retrieve the trait information - let impl_expr = get_trait_info(s, generics, assoc); + // Retrieve the trait information + let impl_expr = get_trait_info(s, generics, assoc); - ConstantExprKind::TraitConst { impl_expr, name } -} + ConstantExprKind::TraitConst { impl_expr, name } + } -impl ConstantExprKind { - pub fn decorate(self, ty: Ty, span: Span) -> Decorated { - Decorated { - contents: Box::new(self), - hir_id: None, - attributes: vec![], - ty, - span, + impl ConstantExprKind { + pub fn decorate(self, ty: Ty, span: Span) -> Decorated { + Decorated { + contents: Box::new(self), + hir_id: None, + attributes: vec![], + ty, + span, + } } } -} -pub enum TranslateUnevalRes { - // TODO: rename - GlobalName(ConstantExprKind), - EvaluatedConstant(T), -} + pub enum TranslateUnevalRes { + // TODO: rename + GlobalName(ConstantExprKind), + EvaluatedConstant(T), + } -pub trait ConstantExt<'tcx>: Sized + std::fmt::Debug { - fn eval_constant>(&self, s: &S) -> Option; - - /// Performs a one-step translation of a constant. - /// - When a constant refers to a named top-level constant, we want to use that, thus we translate the constant to a `ConstantExprKind::GlobalName`. This is captured by the variant `TranslateUnevalRes::GlobalName`. - /// - When a constant refers to a anonymous top-level constant, we evaluate it. If the evaluation fails, we report an error: we expect every AnonConst to be reducible. Otherwise, we return the variant `TranslateUnevalRes::EvaluatedConstant`. - fn translate_uneval( - &self, - s: &impl UnderOwnerState<'tcx>, - ucv: rustc_middle::ty::UnevaluatedConst<'tcx>, - ) -> TranslateUnevalRes { - let tcx = s.base().tcx; - if is_anon_const(ucv.def, tcx) { - TranslateUnevalRes::EvaluatedConstant(self.eval_constant(s).unwrap_or_else(|| { - // TODO: This is triggered when compiling using `generic_const_exprs` - supposely_unreachable_fatal!(s, "TranslateUneval"; {self, ucv}); - })) - } else { - let cv = if let Some(assoc) = s.base().tcx.opt_associated_item(ucv.def) { - if assoc.trait_item_def_id.is_some() { - // This must be a trait declaration constant - trait_const_to_constant_expr_kind(s, ucv.def, ucv.args, &assoc) + pub trait ConstantExt<'tcx>: Sized + std::fmt::Debug { + fn eval_constant>(&self, s: &S) -> Option; + + /// Performs a one-step translation of a constant. + /// - When a constant refers to a named top-level constant, we want to use that, thus we translate the constant to a `ConstantExprKind::GlobalName`. This is captured by the variant `TranslateUnevalRes::GlobalName`. + /// - When a constant refers to a anonymous top-level constant, we evaluate it. If the evaluation fails, we report an error: we expect every AnonConst to be reducible. Otherwise, we return the variant `TranslateUnevalRes::EvaluatedConstant`. + fn translate_uneval( + &self, + s: &impl UnderOwnerState<'tcx>, + ucv: rustc_middle::ty::UnevaluatedConst<'tcx>, + ) -> TranslateUnevalRes { + let tcx = s.base().tcx; + if is_anon_const(ucv.def, tcx) { + TranslateUnevalRes::EvaluatedConstant(self.eval_constant(s).unwrap_or_else(|| { + // TODO: This is triggered when compiling using `generic_const_exprs` + supposely_unreachable_fatal!(s, "TranslateUneval"; {self, ucv}); + })) + } else { + let cv = if let Some(assoc) = s.base().tcx.opt_associated_item(ucv.def) { + if assoc.trait_item_def_id.is_some() { + // This must be a trait declaration constant + trait_const_to_constant_expr_kind(s, ucv.def, ucv.args, &assoc) + } else { + // Constant appearing in an inherent impl block. + + // Solve the trait obligations + let parent_def_id = tcx.parent(ucv.def); + let param_env = s.param_env(); + let trait_refs = + solve_item_traits(s, param_env, parent_def_id, ucv.args, None); + + // Convert + let id = ucv.def.sinto(s); + let generics = ucv.args.sinto(s); + ConstantExprKind::GlobalName { + id, + generics, + trait_refs, + } + } } else { - // Constant appearing in an inherent impl block. - - // Solve the trait obligations - let parent_def_id = tcx.parent(ucv.def); - let param_env = s.param_env(); - let trait_refs = solve_item_traits(s, param_env, parent_def_id, ucv.args, None); - - // Convert + // Top-level constant. + assert!(ucv.args.is_empty(), "top-level constant has generics?"); let id = ucv.def.sinto(s); - let generics = ucv.args.sinto(s); ConstantExprKind::GlobalName { id, - generics, - trait_refs, + generics: vec![], + trait_refs: vec![], } - } - } else { - // Top-level constant. - assert!(ucv.args.is_empty(), "top-level constant has generics?"); - let id = ucv.def.sinto(s); - ConstantExprKind::GlobalName { - id, - generics: vec![], - trait_refs: vec![], - } - }; - TranslateUnevalRes::GlobalName(cv) + }; + TranslateUnevalRes::GlobalName(cv) + } } } -} -impl<'tcx> ConstantExt<'tcx> for ty::Const<'tcx> { - fn eval_constant>(&self, s: &S) -> Option { - let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; - let evaluated = ty::Const::new(s.base().tcx, ty::ConstKind::Value(evaluated), self.ty()); - (&evaluated != self).then_some(evaluated) + impl<'tcx> ConstantExt<'tcx> for ty::Const<'tcx> { + fn eval_constant>(&self, s: &S) -> Option { + let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; + let evaluated = + ty::Const::new(s.base().tcx, ty::ConstKind::Value(evaluated), self.ty()); + (&evaluated != self).then_some(evaluated) + } } -} -impl<'tcx> ConstantExt<'tcx> for mir::ConstantKind<'tcx> { - fn eval_constant>(&self, s: &S) -> Option { - let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; - let evaluated = mir::ConstantKind::Val(evaluated, self.ty()); - (&evaluated != self).then_some(evaluated) + impl<'tcx> ConstantExt<'tcx> for mir::ConstantKind<'tcx> { + fn eval_constant>(&self, s: &S) -> Option { + let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; + let evaluated = mir::ConstantKind::Val(evaluated, self.ty()); + (&evaluated != self).then_some(evaluated) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Const<'tcx> { - fn sinto(&self, s: &S) -> ConstantExpr { - use rustc_middle::query::Key; - let span = self.default_span(s.base().tcx); - let kind = match self.kind() { - ty::ConstKind::Param(p) => ConstantExprKind::ConstRef { id: p.sinto(s) }, - ty::ConstKind::Infer(..) => fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self), - - ty::ConstKind::Unevaluated(ucv) => match self.translate_uneval(s, ucv) { - TranslateUnevalRes::EvaluatedConstant(c) => return c.sinto(s), - TranslateUnevalRes::GlobalName(c) => c, - }, - ty::ConstKind::Value(valtree) => { - return valtree_to_constant_expr(s, valtree, self.ty(), span) - } - ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"), - ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e), + #[cfg(feature = "full")] + impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Const<'tcx> { + fn sinto(&self, s: &S) -> ConstantExpr { + use rustc_middle::query::Key; + let span = self.default_span(s.base().tcx); + let kind = match self.kind() { + ty::ConstKind::Param(p) => ConstantExprKind::ConstRef { id: p.sinto(s) }, + ty::ConstKind::Infer(..) => { + fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self) + } - ty::ConstKind::Bound(i, bound) => { - supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound, self.ty()}); - } - _ => fatal!(s[span], "unexpected case"), - }; - kind.decorate(self.ty().sinto(s), span.sinto(s)) + ty::ConstKind::Unevaluated(ucv) => match self.translate_uneval(s, ucv) { + TranslateUnevalRes::EvaluatedConstant(c) => return c.sinto(s), + TranslateUnevalRes::GlobalName(c) => c, + }, + ty::ConstKind::Value(valtree) => { + return valtree_to_constant_expr(s, valtree, self.ty(), span) + } + ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"), + ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e), + + ty::ConstKind::Bound(i, bound) => { + supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound, self.ty()}); + } + _ => fatal!(s[span], "unexpected case"), + }; + kind.decorate(self.ty().sinto(s), span.sinto(s)) + } } -} -// #[tracing::instrument(skip(s))] -pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - valtree: rustc_middle::ty::ValTree<'tcx>, - ty: rustc_middle::ty::Ty<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - let kind = match (valtree, ty.kind()) { + // #[tracing::instrument(skip(s))] + pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + valtree: rustc_middle::ty::ValTree<'tcx>, + ty: rustc_middle::ty::Ty<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + let kind = match (valtree, ty.kind()) { (_, ty::Ref(_, inner_ty, _)) => { ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span)) } @@ -489,100 +498,108 @@ pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( {valtree, ty} ), }; - kind.decorate(ty.sinto(s), span.sinto(s)) -} + kind.decorate(ty.sinto(s), span.sinto(s)) + } -pub(crate) fn const_value_reference_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - val: rustc_middle::mir::interpret::ConstValue<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - let tcx = s.base().tcx; - - let dc = tcx - .try_destructure_mir_constant_for_diagnostics((val, ty)) - .s_unwrap(s); - - // Iterate over the fields, which should be values - assert!(dc.variant.is_none()); - - // The type should be tuple - let hax_ty = ty.sinto(s); - match &hax_ty { - Ty::Tuple(_) => (), - _ => { - fatal!(s[span], "Expected the type to be tuple: {:?}", val) - } - }; + pub(crate) fn const_value_reference_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + val: rustc_middle::mir::interpret::ConstValue<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + let tcx = s.base().tcx; - // Below: we are mutually recursive with [const_value_to_constant_expr], - // which takes a [ConstantKind] as input, but it should be - // ok because we call it on a strictly smaller value. - let fields: Vec = dc - .fields - .iter() - .copied() - .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)) - .collect(); - (ConstantExprKind::Tuple { fields }).decorate(hax_ty, span.sinto(s)) -} + let dc = tcx + .try_destructure_mir_constant_for_diagnostics((val, ty)) + .s_unwrap(s); + + // Iterate over the fields, which should be values + assert!(dc.variant.is_none()); -pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - val: rustc_middle::mir::interpret::ConstValue<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - use rustc_middle::mir::interpret::ConstValue; - match val { - ConstValue::Scalar(scalar) => scalar_to_constant_expr(s, ty, &scalar, span), - ConstValue::Indirect { .. } => const_value_reference_to_constant_expr(s, ty, val, span), - ConstValue::Slice { data, start, end } => { - let start = start.try_into().unwrap(); - let end = end.try_into().unwrap(); - // This is outside of the interpreter, so we are okay to use - // `inspect_with_uninit_and_ptr_outside_interpreter`. Moreover this is a string/byte - // literal, so we don't have to care about initialization. - // This is copied from `ConstantValue::try_get_slice_bytes_for_diagnostics`, available - // only in a more recent rustc version. - let slice: &[u8] = data - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(start..end); - ConstantExprKind::Literal(ConstantLiteral::byte_str(slice.to_vec(), StrStyle::Cooked)) + // The type should be tuple + let hax_ty = ty.sinto(s); + match &hax_ty { + Ty::Tuple(_) => (), + _ => { + fatal!(s[span], "Expected the type to be tuple: {:?}", val) + } + }; + + // Below: we are mutually recursive with [const_value_to_constant_expr], + // which takes a [ConstantKind] as input, but it should be + // ok because we call it on a strictly smaller value. + let fields: Vec = dc + .fields + .iter() + .copied() + .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)) + .collect(); + (ConstantExprKind::Tuple { fields }).decorate(hax_ty, span.sinto(s)) + } + + pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + val: rustc_middle::mir::interpret::ConstValue<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + use rustc_middle::mir::interpret::ConstValue; + match val { + ConstValue::Scalar(scalar) => scalar_to_constant_expr(s, ty, &scalar, span), + ConstValue::Indirect { .. } => const_value_reference_to_constant_expr(s, ty, val, span), + ConstValue::Slice { data, start, end } => { + let start = start.try_into().unwrap(); + let end = end.try_into().unwrap(); + // This is outside of the interpreter, so we are okay to use + // `inspect_with_uninit_and_ptr_outside_interpreter`. Moreover this is a string/byte + // literal, so we don't have to care about initialization. + // This is copied from `ConstantValue::try_get_slice_bytes_for_diagnostics`, available + // only in a more recent rustc version. + let slice: &[u8] = data + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(start..end); + ConstantExprKind::Literal(ConstantLiteral::byte_str( + slice.to_vec(), + StrStyle::Cooked, + )) .decorate(ty.sinto(s), span.sinto(s)) - } - ConstValue::ZeroSized { .. } => { - // Should be unit - let hty = ty.sinto(s); - let cv = match &hty { - Ty::Tuple(tys) if tys.is_empty() => ConstantExprKind::Tuple { fields: Vec::new() }, - Ty::Arrow(_) => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, args) => { - let (def_id, generics, generics_impls, method_impl) = - get_function_from_def_id_and_generics(s, *def_id, args); - - ConstantExprKind::FnPtr { - def_id, - generics, - generics_impls, - method_impl, - } + } + ConstValue::ZeroSized { .. } => { + // Should be unit + let hty = ty.sinto(s); + let cv = match &hty { + Ty::Tuple(tys) if tys.is_empty() => { + ConstantExprKind::Tuple { fields: Vec::new() } } - kind => { - fatal!(s[span], "Unexpected:"; {kind}) + Ty::Arrow(_) => match ty.kind() { + rustc_middle::ty::TyKind::FnDef(def_id, args) => { + let (def_id, generics, generics_impls, method_impl) = + get_function_from_def_id_and_generics(s, *def_id, args); + + ConstantExprKind::FnPtr { + def_id, + generics, + generics_impls, + method_impl, + } + } + kind => { + fatal!(s[span], "Unexpected:"; {kind}) + } + }, + _ => { + fatal!( + s[span], + "Expected the type to be tuple or arrow"; + {val, ty} + ) } - }, - _ => { - fatal!( - s[span], - "Expected the type to be tuple or arrow"; - {val, ty} - ) - } - }; + }; - cv.decorate(hty, span.sinto(s)) + cv.decorate(hty, span.sinto(s)) + } } } } +#[cfg(feature = "full")] +pub use full::*; diff --git a/frontend/exporter/src/index_vec.rs b/frontend/exporter/src/index_vec.rs index 6fdeecb88..45ab2bc4d 100644 --- a/frontend/exporter/src/index_vec.rs +++ b/frontend/exporter/src/index_vec.rs @@ -3,11 +3,12 @@ use crate::prelude::*; #[derive( Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, )] -pub struct IndexVec { +pub struct IndexVec { pub raw: Vec, _marker: std::marker::PhantomData, } +#[cfg(feature = "full")] impl Into> for rustc_index::IndexVec { fn into(self) -> IndexVec { IndexVec { @@ -17,6 +18,7 @@ impl Into> for rustc_index::IndexVec std::ops::Deref for IndexVec { type Target = rustc_index::IndexSlice; fn deref(&self) -> &Self::Target { @@ -24,12 +26,14 @@ impl std::ops::Deref for IndexVec { } } +#[cfg(feature = "full")] impl std::ops::DerefMut for IndexVec { fn deref_mut(&mut self) -> &mut Self::Target { Self::Target::from_raw_mut(&mut self.raw) } } +#[cfg(feature = "full")] impl< S, J: rustc_index::Idx, @@ -53,9 +57,10 @@ macro_rules! make_idx_wrapper { pub enum $type { $type(usize), } + #[cfg(feature = "full")] const _: () = { - use rustc_index::Idx; type OriginalType = $($mod::)+$type; + use rustc_index::Idx; impl Idx for $type { fn new(idx: usize) -> Self { $type::$type(idx) diff --git a/frontend/exporter/src/lib.rs b/frontend/exporter/src/lib.rs index f15880286..610f818e8 100644 --- a/frontend/exporter/src/lib.rs +++ b/frontend/exporter/src/lib.rs @@ -11,41 +11,48 @@ #![feature(return_position_impl_trait_in_trait)] #![allow(rustdoc::private_intra_doc_links)] -extern crate rustc_abi; -extern crate rustc_ast; -extern crate rustc_ast_pretty; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_errors; -extern crate rustc_hir; -extern crate rustc_hir_analysis; -extern crate rustc_index; -extern crate rustc_infer; -extern crate rustc_interface; -extern crate rustc_middle; -extern crate rustc_mir_build; -extern crate rustc_session; -extern crate rustc_span; -extern crate rustc_target; -extern crate rustc_trait_selection; -extern crate rustc_type_ir; +cfg_if::cfg_if! { + if #[cfg(feature = "full")] { + extern crate rustc_abi; + extern crate rustc_ast; + extern crate rustc_ast_pretty; + extern crate rustc_data_structures; + extern crate rustc_driver; + extern crate rustc_errors; + extern crate rustc_hir; + extern crate rustc_hir_analysis; + extern crate rustc_index; + extern crate rustc_infer; + extern crate rustc_interface; + extern crate rustc_middle; + extern crate rustc_mir_build; + extern crate rustc_session; + extern crate rustc_span; + extern crate rustc_target; + extern crate rustc_trait_selection; + extern crate rustc_type_ir; + } +} + +cfg_if::cfg_if! { + if #[cfg(feature = "full")] { + mod deterministic_hash; + mod rustc_utils; + mod utils; + + pub mod state; + pub use sinto::SInto; + } +} mod body; mod constant_utils; -mod rustc_utils; -pub mod state; -mod types; - -mod deterministic_hash; mod index_vec; mod prelude; - -pub use hax_frontend_exporter_options as options; -pub use prelude::*; - mod sinto; mod traits; -mod utils; +mod types; pub use hax_adt_into::AdtInto; -pub use sinto::SInto; +pub use hax_frontend_exporter_options as options; +pub use prelude::*; diff --git a/frontend/exporter/src/prelude.rs b/frontend/exporter/src/prelude.rs index 977d3d4c5..a3f416065 100644 --- a/frontend/exporter/src/prelude.rs +++ b/frontend/exporter/src/prelude.rs @@ -1,4 +1,3 @@ -pub(crate) use crate::utils::*; pub use crate::*; pub use schemars::{schema_for, JsonSchema}; pub use serde::{Deserialize, Serialize}; @@ -9,7 +8,14 @@ pub use std::rc::Rc; pub use crate::body::*; pub use crate::constant_utils::*; pub use crate::index_vec::*; -pub use crate::rustc_utils::*; -pub use crate::state::*; pub use crate::traits::*; pub use crate::types::*; + +#[cfg(feature = "full")] +mod full_prelude { + pub use crate::rustc_utils::*; + pub use crate::state::*; + pub(crate) use crate::utils::*; +} +#[cfg(feature = "full")] +pub use full_prelude::*; diff --git a/frontend/exporter/src/sinto.rs b/frontend/exporter/src/sinto.rs index 6fedd7267..bc0fbae80 100644 --- a/frontend/exporter/src/sinto.rs +++ b/frontend/exporter/src/sinto.rs @@ -1,6 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +#[cfg(feature = "full")] pub trait SInto { fn sinto(&self, s: &S) -> To; } @@ -14,6 +15,7 @@ macro_rules! sinto_todo { todo: String }, } + #[cfg(feature = "full")] impl<$($($lts,)*)? S> SInto for $($mod)::+::$type$(<$($lts,)*>)? { fn sinto(&self, _: &S) -> $renamed { $renamed::$type{todo: format!("{:?}", self)} @@ -29,6 +31,7 @@ macro_rules! sinto_todo { macro_rules! sinto_as_usize { ($($mod:ident)::+, $type:ident$(<$($lts:lifetime),*$(,)?>)?) => { pub type $type = usize; + #[cfg(feature = "full")] impl<$($($lts,)*)? S> SInto for $($mod)::+::$type$(<$($lts,)*>)? { fn sinto(&self, _: &S) -> $type { self.as_usize() @@ -51,28 +54,33 @@ mod test { sinto_todo!(test, Foo); // sinto_as_usize!(test, Foo); +#[cfg(feature = "full")] impl, R: SInto> SInto for (L, R) { fn sinto(&self, s: &S) -> (LL, RR) { (self.0.sinto(s), self.1.sinto(s)) } } +#[cfg(feature = "full")] impl> SInto> for Option { fn sinto(&self, s: &S) -> Option { self.as_ref().map(|x| x.sinto(s)) } } +#[cfg(feature = "full")] impl> SInto for Box { fn sinto(&self, s: &S) -> D { let box x = self; x.sinto(s) } } +#[cfg(feature = "full")] impl> SInto> for [T] { fn sinto(&self, s: &S) -> Vec { self.into_iter().map(|x| x.sinto(s)).collect() } } +#[cfg(feature = "full")] impl> SInto> for Box<[T]> { fn sinto(&self, s: &S) -> Vec { let box x = self; @@ -80,11 +88,13 @@ impl> SInto> for Box<[T]> { } } +#[cfg(feature = "full")] impl> SInto> for Vec { fn sinto(&self, s: &S) -> Vec { self.into_iter().map(|x| x.sinto(s)).collect() } } +#[cfg(feature = "full")] impl SInto> for rustc_data_structures::sync::Lrc<[u8]> { fn sinto(&self, _s: &S) -> Vec { (**self).iter().cloned().collect() @@ -93,6 +103,7 @@ impl SInto> for rustc_data_structures::sync::Lrc<[u8]> { macro_rules! sinto_clone { ($t:ty) => { + #[cfg(feature = "full")] impl SInto for $t { fn sinto(&self, _: &S) -> $t { self.clone() diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 2b70d4df9..b805e00c5 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -169,7 +169,7 @@ mk!( } ); -pub use types::*; +pub use self::types::*; impl<'tcx> State, (), (), ()> { pub fn new( diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 648e45092..106b79078 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -70,449 +70,467 @@ pub struct ImplExpr { pub args: Vec, } -// FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 -pub(crate) mod search_clause { - use crate::prelude::UnderOwnerState; - use crate::rustc_utils::*; - use crate::{IntoPredicateId, PredicateId}; - use rustc_middle::ty::*; +#[cfg(feature = "full")] +mod full { + use super::*; - fn predicates_to_poly_trait_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: impl Iterator>, - generics: GenericArgsRef<'tcx>, - ) -> impl Iterator> { - predicates - .map(move |pred| pred.kind().subst(tcx, generics)) - .filter_map(|pred| pred.as_poly_trait_predicate()) - } - - #[derive(Clone, Debug)] - pub enum PathChunk<'tcx> { - AssocItem { - item: AssocItem, - predicate: PolyTraitPredicate<'tcx>, - predicate_id: PredicateId, - index: usize, - }, - Parent { - predicate: PolyTraitPredicate<'tcx>, - predicate_id: PredicateId, - index: usize, - }, - } - pub type Path<'tcx> = Vec>; + // FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 + pub(crate) mod search_clause { + use crate::prelude::UnderOwnerState; + use crate::rustc_utils::*; + use crate::{IntoPredicateId, PredicateId}; + use rustc_middle::ty::*; - /// Custom equality on `Predicate`s. - /// - /// Sometimes Rustc inserts extra generic arguments: I noticed - /// some `__H` second argument given to core::hash::Hash for - /// instance. `__H` seems to be inserted in [1]. Such extra - /// arguments seems to be ignored by `default_print_def_path` [2]. - /// - /// Hence, for now, equality is decided by comparing the debug - /// string representations of `Predicate`s. - /// - /// Note there exist also predicates that are different, - /// `Eq`-wise, but whose `sinto` counterpart are equal. - /// - /// TODO: figure out how to implement this function in a sane way. - /// - /// [1]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_builtin_macros/src/deriving/hash.rs#L20 - /// [2]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_middle/src/ty/print/mod.rs#L141 - fn predicate_equality<'tcx, S: UnderOwnerState<'tcx>>( - x: Predicate<'tcx>, - y: Predicate<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - s: &S, - ) -> bool { - let tcx = s.base().tcx; - let erase_and_norm = - |x| tcx.erase_regions(tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x)); - // Lifetime and constantness are irrelevant when resolving instances - let x = erase_and_norm(x); - let y = erase_and_norm(y); - let sx = format!("{:?}", x.kind().skip_binder()); - let sy = format!("{:?}", y.kind().skip_binder()); - let result = sx == sy; - const DEBUG: bool = false; - if DEBUG && result { - use crate::{Predicate, SInto}; - let xs: Predicate = x.sinto(s); - let ys: Predicate = y.sinto(s); - if x != y { - eprintln!("######################## predicate_equality ########################"); - eprintln!("x={:#?}", x); - eprintln!("y={:#?}", y); - eprintln!("######################## sinto ########################"); - eprintln!("sinto(x)={:#?}", xs); - eprintln!("sinto(y)={:#?}", ys); - } + fn predicates_to_poly_trait_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: impl Iterator>, + generics: GenericArgsRef<'tcx>, + ) -> impl Iterator> { + predicates + .map(move |pred| pred.kind().subst(tcx, generics)) + .filter_map(|pred| pred.as_poly_trait_predicate()) } - result - } - #[extension_traits::extension(pub trait TraitPredicateExt)] - impl<'tcx, S: UnderOwnerState<'tcx>> PolyTraitPredicate<'tcx> { - #[tracing::instrument(level = "trace", skip(s))] - fn parents_trait_predicates(self, s: &S) -> Vec<(usize, PolyTraitPredicate<'tcx>)> { - let tcx = s.base().tcx; - let predicates = tcx - .predicates_defined_on_or_above(self.def_id()) - .into_iter() - .map(|apred| apred.predicate); - predicates_to_poly_trait_predicates(tcx, predicates, self.skip_binder().trait_ref.args) - .enumerate() - .collect() + #[derive(Clone, Debug)] + pub enum PathChunk<'tcx> { + AssocItem { + item: AssocItem, + predicate: PolyTraitPredicate<'tcx>, + predicate_id: PredicateId, + index: usize, + }, + Parent { + predicate: PolyTraitPredicate<'tcx>, + predicate_id: PredicateId, + index: usize, + }, } - #[tracing::instrument(level = "trace", skip(s))] - fn associated_items_trait_predicates( - self, + pub type Path<'tcx> = Vec>; + + /// Custom equality on `Predicate`s. + /// + /// Sometimes Rustc inserts extra generic arguments: I noticed + /// some `__H` second argument given to core::hash::Hash for + /// instance. `__H` seems to be inserted in [1]. Such extra + /// arguments seems to be ignored by `default_print_def_path` [2]. + /// + /// Hence, for now, equality is decided by comparing the debug + /// string representations of `Predicate`s. + /// + /// Note there exist also predicates that are different, + /// `Eq`-wise, but whose `sinto` counterpart are equal. + /// + /// TODO: figure out how to implement this function in a sane way. + /// + /// [1]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_builtin_macros/src/deriving/hash.rs#L20 + /// [2]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_middle/src/ty/print/mod.rs#L141 + fn predicate_equality<'tcx, S: UnderOwnerState<'tcx>>( + x: Predicate<'tcx>, + y: Predicate<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, s: &S, - ) -> Vec<( - AssocItem, - EarlyBinder)>>, - )> { + ) -> bool { let tcx = s.base().tcx; - tcx.associated_items(self.def_id()) - .in_definition_order() - .filter(|item| item.kind == AssocKind::Type) - .copied() - .map(|item| { - let bounds = tcx.item_bounds(item.def_id).map_bound(|clauses| { - predicates_to_poly_trait_predicates( - tcx, - clauses.into_iter().map(|clause| clause.as_predicate()), - self.skip_binder().trait_ref.args, - ) - .enumerate() - .collect() - }); - (item, bounds) - }) - .collect() + let erase_and_norm = + |x| tcx.erase_regions(tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x)); + // Lifetime and constantness are irrelevant when resolving instances + let x = erase_and_norm(x); + let y = erase_and_norm(y); + let sx = format!("{:?}", x.kind().skip_binder()); + let sy = format!("{:?}", y.kind().skip_binder()); + let result = sx == sy; + const DEBUG: bool = false; + if DEBUG && result { + use crate::{Predicate, SInto}; + let xs: Predicate = x.sinto(s); + let ys: Predicate = y.sinto(s); + if x != y { + eprintln!( + "######################## predicate_equality ########################" + ); + eprintln!("x={:#?}", x); + eprintln!("y={:#?}", y); + eprintln!( + "######################## sinto ########################" + ); + eprintln!("sinto(x)={:#?}", xs); + eprintln!("sinto(y)={:#?}", ys); + } + } + result } - #[tracing::instrument(level = "trace", skip(s))] - fn path_to( - self, - s: &S, - target: PolyTraitRef<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> Option> { - let tcx = s.base().tcx; - if predicate_equality( - self.to_predicate(tcx), - target.to_predicate(tcx), - param_env, - s, - ) { - return Some(vec![]); + #[extension_traits::extension(pub trait TraitPredicateExt)] + impl<'tcx, S: UnderOwnerState<'tcx>> PolyTraitPredicate<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] + fn parents_trait_predicates(self, s: &S) -> Vec<(usize, PolyTraitPredicate<'tcx>)> { + let tcx = s.base().tcx; + let predicates = tcx + .predicates_defined_on_or_above(self.def_id()) + .into_iter() + .map(|apred| apred.predicate); + predicates_to_poly_trait_predicates( + tcx, + predicates, + self.skip_binder().trait_ref.args, + ) + .enumerate() + .collect() + } + #[tracing::instrument(level = "trace", skip(s))] + fn associated_items_trait_predicates( + self, + s: &S, + ) -> Vec<( + AssocItem, + EarlyBinder)>>, + )> { + let tcx = s.base().tcx; + tcx.associated_items(self.def_id()) + .in_definition_order() + .filter(|item| item.kind == AssocKind::Type) + .copied() + .map(|item| { + let bounds = tcx.item_bounds(item.def_id).map_bound(|clauses| { + predicates_to_poly_trait_predicates( + tcx, + clauses.into_iter().map(|clause| clause.as_predicate()), + self.skip_binder().trait_ref.args, + ) + .enumerate() + .collect() + }); + (item, bounds) + }) + .collect() } - let recurse = |p: Self| { - if p == self { - return None; + #[tracing::instrument(level = "trace", skip(s))] + fn path_to( + self, + s: &S, + target: PolyTraitRef<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> Option> { + let tcx = s.base().tcx; + if predicate_equality( + self.to_predicate(tcx), + target.to_predicate(tcx), + param_env, + s, + ) { + return Some(vec![]); } - p.path_to(s, target, param_env) - }; - fn cons(hd: T, tail: Vec) -> Vec { - vec![hd].into_iter().chain(tail.into_iter()).collect() - } - self.parents_trait_predicates(s) - .into_iter() - .filter_map(|(index, p)| { - recurse(p).map(|path| { - cons( - PathChunk::Parent { - predicate: p, - predicate_id: p.predicate_id(s), - index, - }, - path, - ) + + let recurse = |p: Self| { + if p == self { + return None; + } + p.path_to(s, target, param_env) + }; + fn cons(hd: T, tail: Vec) -> Vec { + vec![hd].into_iter().chain(tail.into_iter()).collect() + } + self.parents_trait_predicates(s) + .into_iter() + .filter_map(|(index, p)| { + recurse(p).map(|path| { + cons( + PathChunk::Parent { + predicate: p, + predicate_id: p.predicate_id(s), + index, + }, + path, + ) + }) }) - }) - .max_by_key(|path| path.len()) - .or_else(|| { - self.associated_items_trait_predicates(s) - .into_iter() - .filter_map(|(item, binder)| { - binder.skip_binder().into_iter().find_map(|(index, p)| { - recurse(p).map(|path| { - cons( - PathChunk::AssocItem { - item, - predicate_id: p.predicate_id(s), - predicate: p, - index, - }, - path, - ) + .max_by_key(|path| path.len()) + .or_else(|| { + self.associated_items_trait_predicates(s) + .into_iter() + .filter_map(|(item, binder)| { + binder.skip_binder().into_iter().find_map(|(index, p)| { + recurse(p).map(|path| { + cons( + PathChunk::AssocItem { + item, + predicate_id: p.predicate_id(s), + predicate: p, + index, + }, + path, + ) + }) }) }) - }) - .max_by_key(|path| path.len()) - }) + .max_by_key(|path| path.len()) + }) + } } } -} -impl ImplExprAtom { - fn with_args(self, args: Vec, r#trait: TraitRef) -> ImplExpr { - ImplExpr { - r#impl: self, - args, - r#trait, + impl ImplExprAtom { + fn with_args(self, args: Vec, r#trait: TraitRef) -> ImplExpr { + ImplExpr { + r#impl: self, + args, + r#trait, + } } } -} - -#[tracing::instrument(level = "trace", skip(s))] -fn impl_exprs<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - obligations: &Vec< - rustc_trait_selection::traits::Obligation<'tcx, rustc_middle::ty::Predicate<'tcx>>, - >, -) -> Vec { - obligations - .into_iter() - .flat_map(|obligation| { - obligation - .predicate - .kind() - .as_poly_trait_predicate() - .map(|trait_ref| { - trait_ref - .map_bound(|p| p.trait_ref) - .impl_expr(s, obligation.param_env) - }) - }) - .collect() -} -pub trait IntoImplExpr<'tcx> { - fn impl_expr>( - &self, + #[tracing::instrument(level = "trace", skip(s))] + fn impl_exprs<'tcx, S: UnderOwnerState<'tcx>>( s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr; -} + obligations: &Vec< + rustc_trait_selection::traits::Obligation<'tcx, rustc_middle::ty::Predicate<'tcx>>, + >, + ) -> Vec { + obligations + .into_iter() + .flat_map(|obligation| { + obligation + .predicate + .kind() + .as_poly_trait_predicate() + .map(|trait_ref| { + trait_ref + .map_bound(|p| p.trait_ref) + .impl_expr(s, obligation.param_env) + }) + }) + .collect() + } -impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitPredicate<'tcx> { - fn impl_expr>( - &self, - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr { - use rustc_middle::ty::ToPolyTraitRef; - self.to_poly_trait_ref().impl_expr(s, param_env) + pub trait IntoImplExpr<'tcx> { + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr; } -} -impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> { + + impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitPredicate<'tcx> { + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr { + use rustc_middle::ty::ToPolyTraitRef; + self.to_poly_trait_ref().impl_expr(s, param_env) + } + } + #[tracing::instrument(level = "trace", skip(s))] - fn impl_expr>( - &self, - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr { - use rustc_trait_selection::traits::*; - let trait_ref: Binder = self.sinto(s); - let trait_ref = trait_ref.value; - match select_trait_candidate(s, param_env, *self) { - ImplSource::UserDefined(ImplSourceUserDefinedData { - impl_def_id, - args: generics, - nested, - }) => ImplExprAtom::Concrete { - id: impl_def_id.sinto(s), - generics: generics.sinto(s), - } - .with_args(impl_exprs(s, &nested), trait_ref), - ImplSource::Param(nested) => { - use search_clause::TraitPredicateExt; - let tcx = s.base().tcx; - let predicates = &tcx.predicates_defined_on_or_above(s.owner_id()); - let Some((apred, path)) = predicates.into_iter().find_map(|apred| { - apred + impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> { + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr { + use rustc_trait_selection::traits::*; + let trait_ref: Binder = self.sinto(s); + let trait_ref = trait_ref.value; + match select_trait_candidate(s, param_env, *self) { + ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: generics, + nested, + }) => ImplExprAtom::Concrete { + id: impl_def_id.sinto(s), + generics: generics.sinto(s), + } + .with_args(impl_exprs(s, &nested), trait_ref), + ImplSource::Param(nested) => { + use search_clause::TraitPredicateExt; + let tcx = s.base().tcx; + let predicates = &tcx.predicates_defined_on_or_above(s.owner_id()); + let Some((apred, path)) = predicates.into_iter().find_map(|apred| { + apred + .predicate + .to_opt_poly_trait_pred() + .map(|poly_trait_predicate| poly_trait_predicate) + .and_then(|poly_trait_predicate| { + poly_trait_predicate.path_to(s, self.clone(), param_env) + }) + .map(|path| (apred, path)) + }) else { + supposely_unreachable_fatal!(s, "ImplExprPredNotFound"; { + self, nested, predicates, trait_ref + }) + }; + use rustc_middle::ty::ToPolyTraitRef; + let r#trait = apred .predicate .to_opt_poly_trait_pred() - .map(|poly_trait_predicate| poly_trait_predicate) - .and_then(|poly_trait_predicate| { - poly_trait_predicate.path_to(s, self.clone(), param_env) - }) - .map(|path| (apred, path)) - }) else { - supposely_unreachable_fatal!(s, "ImplExprPredNotFound"; { - self, nested, predicates, trait_ref - }) - }; - use rustc_middle::ty::ToPolyTraitRef; - let r#trait = apred - .predicate - .to_opt_poly_trait_pred() - .s_unwrap(s) - .to_poly_trait_ref() - .sinto(s); - let path = path.sinto(s); - if apred.is_extra_self_predicate { - ImplExprAtom::SelfImpl { r#trait, path } + .s_unwrap(s) + .to_poly_trait_ref() + .sinto(s); + let path = path.sinto(s); + if apred.is_extra_self_predicate { + ImplExprAtom::SelfImpl { r#trait, path } + .with_args(impl_exprs(s, &nested), trait_ref) + } else { + ImplExprAtom::LocalBound { + predicate_id: apred.predicate.predicate_id(s), + r#trait, + path, + } .with_args(impl_exprs(s, &nested), trait_ref) - } else { - ImplExprAtom::LocalBound { - predicate_id: apred.predicate.predicate_id(s), - r#trait, - path, } - .with_args(impl_exprs(s, &nested), trait_ref) } - } - // We ignore the contained obligations here. For example for `(): Send`, the - // obligations contained would be `[(): Send]`, which leads to an infinite loop. There - // might be important obligation shere inother cases; we'll have to see if that comes - // up. - ImplSource::Builtin(source, _ignored) => { - let atom = match source { - BuiltinImplSource::Object { .. } => ImplExprAtom::Dyn, - _ => ImplExprAtom::Builtin { - r#trait: self.skip_binder().sinto(s), - }, - }; - atom.with_args(vec![], trait_ref) + // We ignore the contained obligations here. For example for `(): Send`, the + // obligations contained would be `[(): Send]`, which leads to an infinite loop. There + // might be important obligation shere inother cases; we'll have to see if that comes + // up. + ImplSource::Builtin(source, _ignored) => { + let atom = match source { + BuiltinImplSource::Object { .. } => ImplExprAtom::Dyn, + _ => ImplExprAtom::Builtin { + r#trait: self.skip_binder().sinto(s), + }, + }; + atom.with_args(vec![], trait_ref) + } } } } -} -/// Given a clause `clause` in the context of some impl. block -/// `impl_did`, susbts correctly `Self` from `clause` and (1) derive a -/// `Clause` and (2) resolve an `ImplExpr`. -pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - impl_did: rustc_span::def_id::DefId, - clause: rustc_middle::ty::Clause<'tcx>, - span: rustc_span::Span, -) -> Option<(Clause, ImplExpr, Span)> { - let tcx = s.base().tcx; - let impl_trait_ref = tcx - .impl_trait_ref(impl_did) - .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?; - let original_predicate_id = { - // We don't want the id of the substituted clause id, but the - // original clause id (with, i.e., `Self`) - let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id()); - clause.predicate_id(s) - }; - let new_clause = clause.subst_supertrait(tcx, &impl_trait_ref); - let impl_expr = new_clause - .as_predicate() - .to_opt_poly_trait_pred()? - .impl_expr(s, s.param_env()); - let mut new_clause_no_binder = new_clause.sinto(s); - new_clause_no_binder.id = original_predicate_id; - Some((new_clause_no_binder, impl_expr, span.sinto(s))) -} + /// Given a clause `clause` in the context of some impl. block + /// `impl_did`, susbts correctly `Self` from `clause` and (1) derive a + /// `Clause` and (2) resolve an `ImplExpr`. + pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + impl_did: rustc_span::def_id::DefId, + clause: rustc_middle::ty::Clause<'tcx>, + span: rustc_span::Span, + ) -> Option<(Clause, ImplExpr, Span)> { + let tcx = s.base().tcx; + let impl_trait_ref = tcx + .impl_trait_ref(impl_did) + .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?; + let original_predicate_id = { + // We don't want the id of the substituted clause id, but the + // original clause id (with, i.e., `Self`) + let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id()); + clause.predicate_id(s) + }; + let new_clause = clause.subst_supertrait(tcx, &impl_trait_ref); + let impl_expr = new_clause + .as_predicate() + .to_opt_poly_trait_pred()? + .impl_expr(s, s.param_env()); + let mut new_clause_no_binder = new_clause.sinto(s); + new_clause_no_binder.id = original_predicate_id; + Some((new_clause_no_binder, impl_expr, span.sinto(s))) + } -#[tracing::instrument(level = "trace", skip(s))] -pub fn select_trait_candidate<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>, -) -> rustc_trait_selection::traits::Selection<'tcx> { - let tcx = s.base().tcx; - match copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, trait_ref)) { - Ok(selection) => selection, - Err(error) => fatal!( - s, - "Cannot handle error `{:?}` selecting `{:?}`", - error, - trait_ref - ), + #[tracing::instrument(level = "trace", skip(s))] + pub fn select_trait_candidate<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>, + ) -> rustc_trait_selection::traits::Selection<'tcx> { + let tcx = s.base().tcx; + match copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, trait_ref)) { + Ok(selection) => selection, + Err(error) => fatal!( + s, + "Cannot handle error `{:?}` selecting `{:?}`", + error, + trait_ref + ), + } } -} -pub mod copy_paste_from_rustc { - use rustc_infer::infer::TyCtxtInferExt; - use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; - use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; - use rustc_middle::ty::{self, TyCtxt}; - use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; - use rustc_trait_selection::traits::{ - Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, Unimplemented, - }; + pub mod copy_paste_from_rustc { + use rustc_infer::infer::TyCtxtInferExt; + use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; + use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; + use rustc_middle::ty::{self, TyCtxt}; + use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; + use rustc_trait_selection::traits::{ + Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, + Unimplemented, + }; - /// Attempts to resolve an obligation to an `ImplSource`. The result is - /// a shallow `ImplSource` resolution, meaning that we do not - /// (necessarily) resolve all nested obligations on the impl. Note - /// that type check should guarantee to us that all nested - /// obligations *could be* resolved if we wanted to. - /// - /// This also expects that `trait_ref` is fully normalized. - pub fn codegen_select_candidate<'tcx>( - tcx: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), - ) -> Result, CodegenObligationError> { - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); + /// Attempts to resolve an obligation to an `ImplSource`. The result is + /// a shallow `ImplSource` resolution, meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + /// + /// This also expects that `trait_ref` is fully normalized. + pub fn codegen_select_candidate<'tcx>( + tcx: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), + ) -> Result, CodegenObligationError> + { + let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx - .infer_ctxt() - .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build(); - //~^ HACK `Bubble` is required for - // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs - let mut selcx = SelectionContext::new(&infcx); + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .build(); + //~^ HACK `Bubble` is required for + // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs + let mut selcx = SelectionContext::new(&infcx); - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); - let selection = match selcx.poly_select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), - Err(e) => { - panic!( - "Encountered error `{:?}` selecting `{:?}` during codegen", - e, trait_ref - ) - } - }; + let selection = match selcx.poly_select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + panic!( + "Encountered error `{:?}` selecting `{:?}` during codegen", + e, trait_ref + ) + } + }; - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = >::new(&infcx); - let impl_source = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate.clone()); - predicate - }); + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = >::new(&infcx); + let impl_source = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate.clone()); + predicate + }); - // In principle, we only need to do this so long as `impl_source` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = fulfill_cx.select_all_or_error(&infcx); - if !errors.is_empty() { - // `rustc_monomorphize::collector` assumes there are no type errors. - // Cycle errors are the only post-monomorphization errors possible; emit them now so - // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. - for err in errors { - if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { - infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + } } + return Err(CodegenObligationError::FulfillmentError); } - return Err(CodegenObligationError::FulfillmentError); - } - let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = infcx.tcx.erase_regions(impl_source); + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); - // Opaque types may have gotten their hidden types constrained, but we can ignore them safely - // as they will get constrained elsewhere, too. - // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.take_opaque_types(); + // Opaque types may have gotten their hidden types constrained, but we can ignore them safely + // as they will get constrained elsewhere, too. + // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass + let _ = infcx.take_opaque_types(); - Ok(impl_source) + Ok(impl_source) + } } } +#[cfg(feature = "full")] +pub use full::*; diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 3ac0bc430..b236e2ab2 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1,5 +1,8 @@ use crate::prelude::*; + +#[cfg(feature = "full")] use crate::rustc_middle::query::Key; +#[cfg(feature = "full")] use rustc_middle::ty; impl std::hash::Hash for DefId { @@ -14,6 +17,7 @@ impl std::hash::Hash for DefId { } } +#[cfg(feature = "full")] impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { fn sinto(&self, s: &S) -> DefId { s.base().exported_def_ids.borrow_mut().insert(self.clone()); @@ -31,6 +35,7 @@ impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { } } +#[cfg(feature = "full")] impl From<&DefId> for rustc_span::def_id::DefId { fn from<'tcx>(def_id: &DefId) -> Self { let (krate, index) = def_id.index; @@ -41,6 +46,7 @@ impl From<&DefId> for rustc_span::def_id::DefId { } } +#[cfg(feature = "full")] impl std::convert::From for Path { fn from(v: DefId) -> Vec { std::iter::once(v.krate) @@ -56,6 +62,7 @@ impl std::convert::From for Path { } pub type GlobalIdent = DefId; +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id::LocalDefId { fn sinto(&self, st: &S) -> DefId { self.to_def_id().sinto(st) @@ -188,6 +195,7 @@ pub struct Scope { pub data: ScopeData, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::mir::ConstantKind<'tcx> { @@ -219,18 +227,21 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto // For ConstantKind we merge all the cases (Ty, Val, Unevaluated) into one pub type ConstantKind = ConstantExpr; +#[cfg(feature = "full")] impl SInto for rustc_middle::mir::interpret::AllocId { fn sinto(&self, _: &S) -> u64 { self.0.get() } } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Box { Box::new(self.sinto(s)) } } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { self.kind().sinto(s) @@ -249,6 +260,7 @@ pub struct HirId { } // TODO: If not working: See original +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { fn sinto(&self, s: &S) -> DefId { self.to_def_id().sinto(s) @@ -370,6 +382,7 @@ pub struct Placeholder { pub bound: T, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> for rustc_middle::ty::Placeholder { @@ -391,6 +404,7 @@ pub struct Canonical { /// Reflects [`rustc_middle::ty::CanonicalUserType`] pub type CanonicalUserType = Canonical; +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> for rustc_middle::infer::canonical::Canonical<'tcx, T> { @@ -482,10 +496,11 @@ pub enum VariantDiscr { /// Reflects [`rustc_middle::ty::Visibility`] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum Visibility { +pub enum Visibility { Public, Restricted(Id), } +#[cfg(feature = "full")] impl, U> SInto> for rustc_middle::ty::Visibility { fn sinto(&self, s: &S) -> Visibility { use rustc_middle::ty::Visibility as T; @@ -509,6 +524,7 @@ pub struct FieldDef { pub span: Span, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::FieldDef { fn sinto(&self, s: &S) -> FieldDef { let tcx = s.base().tcx; @@ -614,12 +630,14 @@ pub enum GenericArg { Const(ConstantExpr), } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::GenericArg<'tcx> { fn sinto(&self, s: &S) -> GenericArg { self.unpack().sinto(s) } } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::GenericArgsRef<'tcx> { @@ -672,6 +690,7 @@ pub struct AdtExpr { pub base: Option, } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr<'tcx> { fn sinto(&self, s: &S) -> AdtExpr { let variants = self.adt_def.variants(); @@ -783,6 +802,7 @@ pub struct Span { pub filename: FileName, /// Original rustc span; can be useful for reporting rustc /// diagnostics (this is used in Charon) + #[cfg(feature = "full")] #[serde(skip)] pub rust_span_data: Option, // expn_backtrace: Vec, @@ -818,6 +838,7 @@ const _: () = { } }; +#[cfg(feature = "full")] impl Into for rustc_span::Loc { fn into(self) -> Loc { Loc { @@ -827,6 +848,7 @@ impl Into for rustc_span::Loc { } } +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { fn sinto(&self, s: &S) -> Span { let set: crate::state::ExportedSpans = s.base().exported_spans; @@ -842,6 +864,7 @@ pub struct LocalIdent { pub id: HirId, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir::LocalVarId { fn sinto(&self, s: &S) -> LocalIdent { LocalIdent { @@ -865,6 +888,7 @@ pub struct Spanned { pub node: T, pub span: Span, } +#[cfg(feature = "full")] impl<'s, S: UnderOwnerState<'s>, T: SInto, U> SInto> for rustc_span::source_map::Spanned { @@ -876,6 +900,7 @@ impl<'s, S: UnderOwnerState<'s>, T: SInto, U> SInto> } } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for PathBuf { fn sinto(&self, _: &S) -> String { self.as_path().display().to_string() @@ -899,6 +924,7 @@ pub enum RealFileName { }, } +#[cfg(feature = "full")] impl SInto for rustc_data_structures::stable_hasher::Hash64 { fn sinto(&self, _: &S) -> u64 { self.as_u64() @@ -1125,18 +1151,21 @@ pub struct MacCall { /// string. If you need to reshape that into Rust tokens or construct, /// please use, e.g., `syn`. pub type TokenStream = String; +#[cfg(feature = "full")] impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { fn sinto(&self, _: &S) -> String { rustc_ast_pretty::pprust::tts_to_string(self) } } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::BlockId { fn sinto(&self, s: &S) -> Block { s.thir().blocks[*self].sinto(s) } } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { fn sinto(&self, s: &S) -> Stmt { s.thir().stmts[*self].sinto(s) @@ -1145,8 +1174,10 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { /// While translating expressions, we expect to always have a THIR /// body and an `owner_id` in the state +#[cfg(feature = "full")] pub trait ExprState<'tcx> = UnderOwnerState<'tcx> + HasThir<'tcx>; +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> { fn sinto(&self, s: &S) -> Expr { let (hir_id, attributes) = self.hir_id_and_attributes(s); @@ -1290,12 +1321,14 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> } } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ExprId { fn sinto(&self, s: &S) -> Expr { s.thir().exprs[*self].sinto(s) } } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { fn sinto(&self, s: &S) -> Pat { let rustc_middle::thir::Pat { span, kind, ty } = self; @@ -1335,6 +1368,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { } } +#[cfg(feature = "full")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { fn sinto(&self, s: &S) -> Arm { s.thir().arms[*self].sinto(s) @@ -1367,6 +1401,7 @@ pub enum FloatTy { F64, } +#[cfg(feature = "full")] impl<'tcx, S> SInto for rustc_ast::ast::FloatTy { fn sinto(&self, _: &S) -> FloatTy { use rustc_ast::ast::FloatTy as T; @@ -1377,6 +1412,7 @@ impl<'tcx, S> SInto for rustc_ast::ast::FloatTy { } } +#[cfg(feature = "full")] impl<'tcx, S> SInto for rustc_ast::ast::IntTy { fn sinto(&self, _: &S) -> IntTy { use rustc_ast::ast::IntTy as T; @@ -1390,6 +1426,7 @@ impl<'tcx, S> SInto for rustc_ast::ast::IntTy { } } } +#[cfg(feature = "full")] impl<'tcx, S> SInto for rustc_ast::ast::UintTy { fn sinto(&self, _: &S) -> UintTy { use rustc_ast::ast::UintTy as T; @@ -1458,6 +1495,7 @@ pub struct TypeAndMut { pub mutbl: Mutability, } +#[cfg(feature = "full")] impl> SInto> for rustc_middle::ty::List { fn sinto(&self, s: &S) -> Vec { self.iter().map(|x| x.sinto(s)).collect() @@ -1530,6 +1568,7 @@ pub enum AliasKind { Weak, } +#[cfg(feature = "full")] impl Alias { #[tracing::instrument(level = "trace", skip(s))] fn from<'tcx, S: BaseState<'tcx> + HasOwnerId>( @@ -1778,6 +1817,7 @@ pub struct ReprOptions { pub field_shuffle_seed: u64, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtDef<'tcx> { fn sinto(&self, s: &S) -> AdtDef { AdtDef { @@ -2082,6 +2122,7 @@ pub struct AttrItem { pub tokens: Option, } +#[cfg(feature = "full")] impl SInto for rustc_ast::tokenstream::LazyAttrTokenStream { fn sinto(&self, st: &S) -> String { self.to_attr_token_stream().to_tokenstream().sinto(st) @@ -2446,6 +2487,7 @@ pub enum ExprKind { Todo(String), } +#[cfg(feature = "full")] pub trait ExprKindExt<'tcx> { fn hir_id_and_attributes>( &self, @@ -2457,6 +2499,7 @@ pub trait ExprKindExt<'tcx> { ) -> rustc_middle::thir::Expr<'tcx>; } +#[cfg(feature = "full")] impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { fn hir_id_and_attributes>( &self, @@ -2545,6 +2588,7 @@ pub struct FnHeader { pub type ThirBody = Expr; +#[cfg(feature = "full")] impl<'x, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { fn sinto(self: &rustc_hir::Ty<'x>, s: &S) -> Ty { // **Important:** @@ -2628,6 +2672,7 @@ pub enum WherePredicate { EqPredicate(WhereEqPredicate), } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for rustc_hir::ImplItemRef { @@ -2773,6 +2818,7 @@ pub enum AssocItemKind { Type, } +#[cfg(feature = "full")] impl< 'tcx, S, @@ -3063,6 +3109,7 @@ pub struct TraitItem { pub attributes: ItemAttributes, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for rustc_hir::EnumDef<'tcx> { @@ -3071,6 +3118,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> } } +#[cfg(feature = "full")] impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for rustc_hir::TraitItemRef { @@ -3081,6 +3129,7 @@ impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> } } +#[cfg(feature = "full")] impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> for rustc_hir::Mod<'a> { @@ -3114,6 +3163,7 @@ pub struct ForeignItem { pub vis_span: Span, } +#[cfg(feature = "full")] impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for rustc_hir::ForeignItemRef { @@ -3194,6 +3244,7 @@ pub struct OutlivesPredicate { pub rhs: B, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, A1, A2, B1, B2> SInto> for rustc_middle::ty::OutlivesPredicate where @@ -3222,6 +3273,7 @@ pub enum Term { Const(ConstantExpr), } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<'tcx> { fn sinto(&self, s: &S) -> Term { use rustc_middle::ty::TermKind; @@ -3252,6 +3304,7 @@ pub struct ProjectionPredicate { pub ty: Ty, } +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle::ty::ProjectionPredicate<'tcx> { @@ -3304,6 +3357,7 @@ pub struct Clause { pub id: PredicateId, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clause<'tcx> { fn sinto(&self, s: &S) -> Clause { Clause { @@ -3322,6 +3376,7 @@ pub struct Predicate { pub id: PredicateId, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Predicate<'tcx> { fn sinto(&self, s: &S) -> Predicate { Predicate { @@ -3365,6 +3420,7 @@ pub struct GenericPredicates { pub predicates: Vec<(Predicate, Span)>, } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> for rustc_middle::ty::Binder<'tcx, T1> where @@ -3444,6 +3500,7 @@ pub enum PredicateKind { type GenericBounds = Vec; /// Compute the bounds for the owner registed in the state `s` +#[cfg(feature = "full")] fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> GenericBounds { let tcx = s.base().tcx; @@ -3485,6 +3542,7 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene clauses.sinto(s) } +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::GenericBounds<'tcx> { fn sinto(&self, s: &S) -> GenericBounds { region_bounds_at_current_owner(s) @@ -3522,6 +3580,7 @@ pub struct Item { pub expn_backtrace: Vec, } +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::Item<'tcx> { fn sinto(&self, s: &S) -> Item { let name: String = self.ident.name.to_ident_string(); @@ -3542,6 +3601,7 @@ impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir: } } +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::ItemId { fn sinto(&self, s: &S) -> Item { let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; @@ -3552,6 +3612,7 @@ impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir: /// Reflects [`rustc_span::symbol::Ident`] pub type Ident = (Symbol, Span); +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ident { fn sinto(&self, s: &S) -> Ident { (self.name.sinto(s), self.span.sinto(s)) diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index ef5c7a33c..38ab11f7f 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -13,7 +13,10 @@ pub use serde::{Deserialize, Serialize}; #[cfg(not(feature = "extract_names_mode"))] -use crate::{AdtInto, BaseState, JsonSchema, SInto}; +use crate::{AdtInto, JsonSchema}; + +#[cfg(feature = "full")] +use crate::{BaseState, SInto}; pub type Symbol = String; diff --git a/frontend/exporter/src/types/index.rs b/frontend/exporter/src/types/index.rs index 3ce6a3701..ed580efb7 100644 --- a/frontend/exporter/src/types/index.rs +++ b/frontend/exporter/src/types/index.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::sinto_as_usize; sinto_as_usize!(rustc_middle::ty, DebruijnIndex); sinto_as_usize!(rustc_middle::ty, UniverseIndex); diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 97c19eaae..5da5a5385 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -1,4 +1,6 @@ use crate::prelude::*; + +#[cfg(feature = "full")] use tracing::trace; #[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -35,6 +37,7 @@ pub enum ClearCrossCrate { Set(T), } +#[cfg(feature = "full")] impl> SInto> for rustc_middle::mir::ClearCrossCrate { @@ -63,6 +66,7 @@ pub enum AnalysisPhase { pub type BasicBlocks = IndexVec; +#[cfg(feature = "full")] fn name_of_local( local: rustc_middle::mir::Local, var_debug_info: &Vec, @@ -81,6 +85,7 @@ fn name_of_local( /// Enumerates the kinds of Mir bodies. TODO: use const generics /// instead of an open list of types. +#[cfg(feature = "full")] pub mod mir_kinds { use crate::prelude::{Deserialize, JsonSchema, Serialize}; use rustc_data_structures::steal::Steal; @@ -106,6 +111,7 @@ pub mod mir_kinds { } // TODO: Add [Promoted] MIR } +#[cfg(feature = "full")] pub use mir_kinds::IsMirKind; #[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] @@ -191,6 +197,7 @@ pub enum Operand { Constant(Constant), } +#[cfg(feature = "full")] impl Operand { pub(crate) fn ty(&self) -> &Ty { match self { @@ -207,6 +214,7 @@ pub struct Terminator { pub kind: TerminatorKind, } +#[cfg(feature = "full")] pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + HasOwnerId>( s: &S, def_id: rustc_hir::def_id::DefId, @@ -322,6 +330,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H /// The [Operand] comes from a [TerminatorKind::Call]. /// Only supports calls to top-level functions (which are considered as constants /// by rustc); doesn't support closures for now. +#[cfg(feature = "full")] fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( s: &S, func: &rustc_middle::mir::Operand<'tcx>, @@ -390,6 +399,7 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( } } +#[cfg(feature = "full")] fn translate_terminator_kind_call<'tcx, S: BaseState<'tcx> + HasMir<'tcx> + HasOwnerId>( s: &S, terminator: &rustc_middle::mir::TerminatorKind<'tcx>, @@ -441,6 +451,7 @@ pub struct ScalarInt { // TODO: naming conventions: is "translate" ok? /// Translate switch targets +#[cfg(feature = "full")] fn translate_switch_targets<'tcx, S: UnderOwnerState<'tcx>>( s: &S, switch_ty: &Ty, @@ -668,6 +679,7 @@ pub enum ProjectionElem { } // refactor +#[cfg(feature = "full")] impl<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>> SInto for rustc_middle::mir::Place<'tcx> { @@ -823,6 +835,7 @@ pub struct MirFnSig { pub type MirPolyFnSig = Binder; +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle::ty::FnSig<'tcx> { fn sinto(&self, s: &S) -> MirFnSig { let inputs = self.inputs().sinto(s); @@ -839,6 +852,7 @@ impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle: // TODO: we need this function because sometimes, Rust doesn't infer the proper // typeclass instance. +#[cfg(feature = "full")] pub(crate) fn poly_fn_sig_to_mir_poly_fn_sig<'tcx, S: BaseState<'tcx> + HasOwnerId>( sig: &rustc_middle::ty::PolyFnSig<'tcx>, s: &S, diff --git a/frontend/exporter/src/types/mod.rs b/frontend/exporter/src/types/mod.rs index 00fbdd947..4427aa982 100644 --- a/frontend/exporter/src/types/mod.rs +++ b/frontend/exporter/src/types/mod.rs @@ -5,6 +5,7 @@ mod copied; mod def_id; mod index; mod mir; +#[cfg(feature = "full")] mod mir_traits; mod new; mod replaced; @@ -14,6 +15,7 @@ pub use copied::*; pub use def_id::*; pub use index::*; pub use mir::*; +#[cfg(feature = "full")] pub use mir_traits::*; pub use new::*; pub use replaced::*; diff --git a/frontend/exporter/src/types/new/item_attributes.rs b/frontend/exporter/src/types/new/item_attributes.rs index bfaa141d1..bd2148eb3 100644 --- a/frontend/exporter/src/types/new/item_attributes.rs +++ b/frontend/exporter/src/types/new/item_attributes.rs @@ -15,11 +15,13 @@ impl ItemAttributes { } } +#[cfg(feature = "full")] lazy_static::lazy_static! { pub static ref CORE_EXTRACTION_MODE: bool = std::env::var_os("HAX_CORE_EXTRACTION_MODE") == Some("on".into()); } +#[cfg(feature = "full")] impl ItemAttributes { pub fn from_owner_id<'tcx, S: BaseState<'tcx>>( s: &S, diff --git a/frontend/exporter/src/types/new/predicate_id.rs b/frontend/exporter/src/types/new/predicate_id.rs index 04fa8b49d..7a05edcc7 100644 --- a/frontend/exporter/src/types/new/predicate_id.rs +++ b/frontend/exporter/src/types/new/predicate_id.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use rustc_middle::ty; #[derive( Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, @@ -10,56 +9,63 @@ use rustc_middle::ty; /// uniform and deterministic way. pub struct PredicateId(u64); -/// Implemented by anything that can be assimilated to a predicate. -pub trait IntoPredicateId<'tcx, S: UnderOwnerState<'tcx>> { - /// Compute a consistent `PredicateId` - fn predicate_id(&self, s: &S) -> PredicateId; -} +#[cfg(feature = "full")] +mod full { + use super::*; + use rustc_middle::ty; + /// Implemented by anything that can be assimilated to a predicate. + pub trait IntoPredicateId<'tcx, S: UnderOwnerState<'tcx>> { + /// Compute a consistent `PredicateId` + fn predicate_id(&self, s: &S) -> PredicateId; + } -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Clause<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - self.as_predicate().predicate_id(s) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Clause<'tcx> { + fn predicate_id(&self, s: &S) -> PredicateId { + self.as_predicate().predicate_id(s) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Predicate<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - // Here, we need to be careful about not hashing a `crate::Predicate`, - // but `crate::Binder` instead, - // otherwise we would get into a infinite recursion. - let poly_kind: Binder = self.kind().sinto(s); - PredicateId(deterministic_hash(&poly_kind)) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Predicate<'tcx> { + fn predicate_id(&self, s: &S) -> PredicateId { + // Here, we need to be careful about not hashing a `crate::Predicate`, + // but `crate::Binder` instead, + // otherwise we would get into a infinite recursion. + let poly_kind: Binder = self.kind().sinto(s); + PredicateId(deterministic_hash(&poly_kind)) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::PolyTraitPredicate<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - use ty::ToPredicate; - let predicate: ty::Predicate<'tcx> = (*self).to_predicate(s.base().tcx); - predicate.predicate_id(s) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::PolyTraitPredicate<'tcx> { + fn predicate_id(&self, s: &S) -> PredicateId { + use ty::ToPredicate; + let predicate: ty::Predicate<'tcx> = (*self).to_predicate(s.base().tcx); + predicate.predicate_id(s) + } } -} -/// A `PredicateId` can be mapped to itself via SInto. This is useful -/// for mirroring the type [`traits::search_clause::PathChunk`] as -/// [`traits::ImplExprPathChunk`]. -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for PredicateId { - fn sinto(&self, _s: &S) -> PredicateId { - *self + /// A `PredicateId` can be mapped to itself via SInto. This is useful + /// for mirroring the type [`traits::search_clause::PathChunk`] as + /// [`traits::ImplExprPathChunk`]. + impl<'tcx, S: UnderOwnerState<'tcx>> SInto for PredicateId { + fn sinto(&self, _s: &S) -> PredicateId { + *self + } } -} -/// We need identifiers that are stable across different -/// architectures, different paths (which are observable from -/// `Span`s), etc. -/// Rustc's stable hash is not doing what we want here: it is sensible -/// to the environment. Instead, we first `sinto` and then hash with -/// `deterministic_hash` below. -fn deterministic_hash(x: &T) -> u64 { - use crate::deterministic_hash::DeterministicHasher; - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; - let mut hasher = DeterministicHasher::new(DefaultHasher::new()); - x.hash(&mut hasher); - hasher.finish() + /// We need identifiers that are stable across different + /// architectures, different paths (which are observable from + /// `Span`s), etc. + /// Rustc's stable hash is not doing what we want here: it is sensible + /// to the environment. Instead, we first `sinto` and then hash with + /// `deterministic_hash` below. + fn deterministic_hash(x: &T) -> u64 { + use crate::deterministic_hash::DeterministicHasher; + use std::collections::hash_map::DefaultHasher; + use std::hash::Hasher; + let mut hasher = DeterministicHasher::new(DefaultHasher::new()); + x.hash(&mut hasher); + hasher.finish() + } } +#[cfg(feature = "full")] +pub use full::*; diff --git a/frontend/exporter/src/types/new/typed_constant_kind.rs b/frontend/exporter/src/types/new/typed_constant_kind.rs index 734abc240..7c3eae3cf 100644 --- a/frontend/exporter/src/types/new/typed_constant_kind.rs +++ b/frontend/exporter/src/types/new/typed_constant_kind.rs @@ -6,6 +6,7 @@ pub struct TypedConstantKind { pub constant_kind: ConstantExpr, } +#[cfg(feature = "full")] impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle::mir::ConstantKind<'tcx> { diff --git a/frontend/exporter/src/types/replaced.rs b/frontend/exporter/src/types/replaced.rs index 6af2e21af..d44d758c0 100644 --- a/frontend/exporter/src/types/replaced.rs +++ b/frontend/exporter/src/types/replaced.rs @@ -1,19 +1,24 @@ -use crate::prelude::*; - pub type Path = Vec; +pub type Mutability = bool; -impl<'t, S> SInto for rustc_span::symbol::Symbol { - fn sinto(&self, _s: &S) -> Symbol { - self.to_ident_string() +#[cfg(feature = "full")] +mod full { + use super::*; + use crate::prelude::*; + impl<'t, S> SInto for rustc_span::symbol::Symbol { + fn sinto(&self, _s: &S) -> Symbol { + self.to_ident_string() + } } -} -pub type Mutability = bool; -impl SInto for rustc_hir::Mutability { - fn sinto(&self, _s: &S) -> Mutability { - match self { - rustc_hir::Mutability::Mut => true, - _ => false, + impl SInto for rustc_hir::Mutability { + fn sinto(&self, _s: &S) -> Mutability { + match self { + rustc_hir::Mutability::Mut => true, + _ => false, + } } } } +#[cfg(feature = "full")] +pub use full::*; diff --git a/frontend/exporter/src/types/todo.rs b/frontend/exporter/src/types/todo.rs index 6df174278..d8eaa124f 100644 --- a/frontend/exporter/src/types/todo.rs +++ b/frontend/exporter/src/types/todo.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::sinto_todo; sinto_todo!(rustc_middle::ty, ScalarInt); sinto_todo!(rustc_middle::ty, ExistentialPredicate<'a>); sinto_todo!(rustc_middle::ty, AdtFlags); From 521371cc2af92964e7a48f8b447bec66ea5b95ec Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 12 Jun 2024 10:19:14 +0200 Subject: [PATCH 2/6] refactor: make `hax-engine-names` depends on `hax-frontend-exporter`, w/o `full` This get rids of the `#[path]` introduced https://github.com/hacspec/hax/pull/703 by using the disabling the new `full` feature of `hax-frontend-exporter`. --- Cargo.lock | 1 + engine/names/extract/Cargo.toml | 1 + engine/names/extract/build.rs | 9 +------- frontend/exporter/src/types/def_id.rs | 33 ++++++++------------------- 4 files changed, 13 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1d8e2dee..7c619ec4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,6 +525,7 @@ dependencies = [ "cargo_metadata", "hax-cli-options-engine", "hax-engine-names", + "hax-frontend-exporter", "serde", "serde_json", "tempfile", diff --git a/engine/names/extract/Cargo.toml b/engine/names/extract/Cargo.toml index 3c845ec32..9604ee100 100644 --- a/engine/names/extract/Cargo.toml +++ b/engine/names/extract/Cargo.toml @@ -12,6 +12,7 @@ description = "Helper binary generating an OCaml module" [build-dependencies] hax-cli-options-engine.workspace = true +hax-frontend-exporter.workspace = true serde.workspace = true serde_json.workspace = true cargo_metadata.workspace = true diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 80d22a7e1..2e4a38511 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -2,14 +2,7 @@ use serde_json; use serde_json::Value; use std::process::{Command, Stdio}; -/// Instead of depending on `hax_frontend_exporter` (that links to -/// rustc and exposes a huge number of type definitions and their -/// impls), we just inline a small module here that contains the three -/// type definition we need. See the module for complementary -/// informations. -#[path = "../../../frontend/exporter/src/types/def_id.rs"] -mod hax_frontend_exporter_def_id; -use hax_frontend_exporter_def_id::*; +use hax_frontend_exporter::{DefId, DefPathItem, DisambiguatedDefPathItem}; /// Name of the current crate const HAX_ENGINE_NAMES_CRATE: &str = "hax_engine_names"; diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index 38ab11f7f..2704cf4c5 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -1,28 +1,15 @@ -//! This module contains the type definition for `DefId` and the types -//! `DefId` depends on. -//! -//! This is purposely a very small isolated module: -//! `hax-engine-names-extract` uses those types, but we don't want -//! `hax-engine-names-extract` to have a build dependency on the whole -//! frontend, that double the build times for the Rust part of hax. -//! -//! The feature `extract_names_mode` exists only in the crate -//! `hax-engine-names-extract`, and is used to turn off the derive -//! attributes `AdtInto` and `JsonSchema`. - -pub use serde::{Deserialize, Serialize}; - -#[cfg(not(feature = "extract_names_mode"))] use crate::{AdtInto, JsonSchema}; +pub use serde::{Deserialize, Serialize}; #[cfg(feature = "full")] use crate::{BaseState, SInto}; pub type Symbol = String; -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] -#[cfg_attr(not(feature = "extract_names_mode"), args(<'a, S: BaseState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s))] +#[derive( + Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord, AdtInto, JsonSchema, +)] +#[args(<'a, S: BaseState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s)] /// Reflects [`rustc_hir::definitions::DisambiguatedDefPathData`] pub struct DisambiguatedDefPathItem { pub data: DefPathItem, @@ -30,8 +17,7 @@ pub struct DisambiguatedDefPathItem { } /// Reflects [`rustc_hir::def_id::DefId`] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(not(feature = "extract_names_mode"), derive(JsonSchema))] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub struct DefId { pub krate: String, pub path: Vec, @@ -47,9 +33,10 @@ pub struct DefId { } /// Reflects [`rustc_hir::definitions::DefPathData`] -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] -#[cfg_attr(not(feature = "extract_names_mode"), args(<'ctx, S: BaseState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as state))] +#[derive( + Clone, Debug, AdtInto, JsonSchema, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord, +)] +#[args(<'ctx, S: BaseState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as state)] pub enum DefPathItem { CrateRoot, Impl, From 2493d278fa186d6afdc87d7fe1a1885e828c1070 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 12 Jun 2024 14:19:58 +0200 Subject: [PATCH 3/6] refactor: get rid of crate hax-frontend-exporter-options --- Cargo.lock | 15 +-------------- Cargo.toml | 3 --- cli/driver/Cargo.toml | 1 - cli/driver/src/exporter.rs | 12 ++++++------ cli/options/Cargo.toml | 2 +- cli/options/engine/Cargo.toml | 3 +-- cli/options/src/lib.rs | 8 ++++---- cli/subcommands/Cargo.toml | 2 +- frontend/exporter/Cargo.toml | 1 - frontend/exporter/options/Cargo.toml | 16 ---------------- frontend/exporter/src/lib.rs | 2 +- .../{options/src/lib.rs => src/options.rs} | 2 +- frontend/exporter/src/rustc_utils.rs | 2 +- frontend/exporter/src/state.rs | 14 ++++---------- frontend/exporter/src/traits.rs | 2 +- 15 files changed, 22 insertions(+), 63 deletions(-) delete mode 100644 frontend/exporter/options/Cargo.toml rename frontend/exporter/{options/src/lib.rs => src/options.rs} (99%) diff --git a/Cargo.lock b/Cargo.lock index 7c619ec4b..b8ad5f28e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,7 +134,6 @@ dependencies = [ "hax-cli-options-engine", "hax-diagnostics", "hax-frontend-exporter", - "hax-frontend-exporter-options", "hax-lib-macros-types", "is-terminal", "itertools", @@ -452,7 +451,7 @@ name = "hax-cli-options" version = "0.1.0-pre.1" dependencies = [ "clap", - "hax-frontend-exporter-options", + "hax-frontend-exporter", "path-clean", "schemars", "serde", @@ -467,7 +466,6 @@ dependencies = [ "hax-cli-options", "hax-diagnostics", "hax-frontend-exporter", - "hax-frontend-exporter-options", "itertools", "path-clean", "schemars", @@ -495,7 +493,6 @@ dependencies = [ "hax-cli-options-engine", "hax-diagnostics", "hax-frontend-exporter", - "hax-frontend-exporter-options", "hax-lib-macros-types", "hax-lint", "hax-phase-debug-webapp", @@ -538,7 +535,6 @@ dependencies = [ "cfg-if", "extension-traits", "hax-adt-into", - "hax-frontend-exporter-options", "itertools", "lazy_static", "paste", @@ -548,15 +544,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hax-frontend-exporter-options" -version = "0.1.0-pre.1" -dependencies = [ - "schemars", - "serde", - "serde_json", -] - [[package]] name = "hax-lib" version = "0.1.0-pre.1" diff --git a/Cargo.toml b/Cargo.toml index 6ed486c11..335a13c54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "frontend/exporter", - "frontend/exporter/options", "frontend/diagnostics", "frontend/lint", "cli/options", @@ -22,7 +21,6 @@ members = [ exclude = ["tests"] default-members = [ "frontend/exporter", - "frontend/exporter/options", "frontend/diagnostics", "frontend/lint", "cli/options", @@ -83,7 +81,6 @@ hax-frontend-exporter = { path = "frontend/exporter", version = "=0.1.0-pre.1" } hax-adt-into = { path = "frontend/exporter/adt-into", version = "=0.1.0-pre.1" } hax-cli-options = { path = "cli/options", version = "=0.1.0-pre.1" } hax-cli-options-engine = { path = "cli/options/engine", version = "=0.1.0-pre.1" } -hax-frontend-exporter-options = { path = "frontend/exporter/options", version = "=0.1.0-pre.1" } hax-diagnostics = { path = "frontend/diagnostics", version = "=0.1.0-pre.1" } hax-lint = { path = "frontend/lint", version = "=0.1.0-pre.1" } hax-phase-debug-webapp = { path = "engine/utils/phase-debug-webapp", version = "=0.1.0-pre.1" } diff --git a/cli/driver/Cargo.toml b/cli/driver/Cargo.toml index 0f33501ff..7afd1da74 100644 --- a/cli/driver/Cargo.toml +++ b/cli/driver/Cargo.toml @@ -24,7 +24,6 @@ colored.workspace = true hax-frontend-exporter.workspace = true hax-cli-options.workspace = true hax-cli-options-engine.workspace = true -hax-frontend-exporter-options.workspace = true hax-lint.workspace = true hax-diagnostics.workspace = true hax-lib-macros-types.workspace = true diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index 948fbf5b5..c7b5aee1a 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -157,7 +157,7 @@ fn precompute_local_thir_bodies<'tcx>( /// (I call "THIR'" the AST described in this crate) #[tracing::instrument(skip_all)] fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( - options: &hax_frontend_exporter_options::Options, + options: &hax_frontend_exporter::options::Options, macro_calls: HashMap, tcx: TyCtxt<'tcx>, ) -> ( @@ -278,9 +278,9 @@ pub(crate) struct ExtractionCallbacks { pub macro_calls: HashMap, } -impl From for hax_frontend_exporter_options::Options { - fn from(opts: ExtractionCallbacks) -> hax_frontend_exporter_options::Options { - hax_frontend_exporter_options::Options { +impl From for hax_frontend_exporter::options::Options { + fn from(opts: ExtractionCallbacks) -> hax_frontend_exporter::options::Options { + hax_frontend_exporter::options::Options { inline_macro_calls: opts.inline_macro_calls, } } @@ -323,7 +323,7 @@ impl Callbacks for ExtractionCallbacks { include_extra, } => { struct Driver<'tcx> { - options: hax_frontend_exporter_options::Options, + options: hax_frontend_exporter::options::Options, macro_calls: HashMap, tcx: TyCtxt<'tcx>, @@ -452,7 +452,7 @@ impl Callbacks for ExtractionCallbacks { ) }); let options_frontend = - hax_frontend_exporter_options::Options::from(self.clone()); + hax_frontend_exporter::options::Options::from(self.clone()); let state = hax_frontend_exporter::state::State::new(tcx, options_frontend.clone()); report_diagnostics( diff --git a/cli/options/Cargo.toml b/cli/options/Cargo.toml index f302e3f18..d92b5aaa8 100644 --- a/cli/options/Cargo.toml +++ b/cli/options/Cargo.toml @@ -15,5 +15,5 @@ serde.workspace = true serde_json.workspace = true schemars.workspace = true clap.workspace = true -hax-frontend-exporter-options.workspace = true +hax-frontend-exporter = { workspace = true, features = [] } path-clean = "1.0.1" diff --git a/cli/options/engine/Cargo.toml b/cli/options/engine/Cargo.toml index 2a649bb7b..59c9ed9f8 100644 --- a/cli/options/engine/Cargo.toml +++ b/cli/options/engine/Cargo.toml @@ -17,7 +17,6 @@ itertools.workspace = true clap.workspace = true hax-diagnostics.workspace = true hax-cli-options.workspace = true -hax-frontend-exporter.workspace = true -hax-frontend-exporter-options.workspace = true +hax-frontend-exporter = { workspace = true, features = [] } path-clean = "1.0.1" diff --git a/cli/options/src/lib.rs b/cli/options/src/lib.rs index c50fdc8c8..a71c6045e 100644 --- a/cli/options/src/lib.rs +++ b/cli/options/src/lib.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::fmt; use std::path::{Path, PathBuf}; -pub use hax_frontend_exporter_options::*; +pub use hax_frontend_exporter::options::{self, Namespace}; #[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] pub enum DebugEngineMode { @@ -449,9 +449,9 @@ impl NormalizePaths for Options { } } -impl From for hax_frontend_exporter_options::Options { - fn from(opts: Options) -> hax_frontend_exporter_options::Options { - hax_frontend_exporter_options::Options { +impl From for options::Options { + fn from(opts: Options) -> options::Options { + options::Options { inline_macro_calls: opts.inline_macro_calls, } } diff --git a/cli/subcommands/Cargo.toml b/cli/subcommands/Cargo.toml index 0f8e453f3..f3f3221be 100644 --- a/cli/subcommands/Cargo.toml +++ b/cli/subcommands/Cargo.toml @@ -30,7 +30,7 @@ itertools.workspace = true clap.workspace = true paste = "1.0.11" hax-cli-options.workspace = true -hax-frontend-exporter-options.workspace = true +hax-frontend-exporter = { workspace = true, features = [] } hax-diagnostics.workspace = true path-clean = "1.0.1" tempfile = "3.8" diff --git a/frontend/exporter/Cargo.toml b/frontend/exporter/Cargo.toml index b8a350aa7..3df222e85 100644 --- a/frontend/exporter/Cargo.toml +++ b/frontend/exporter/Cargo.toml @@ -16,7 +16,6 @@ rustc_private=true serde.workspace = true serde_json.workspace = true schemars.workspace = true -hax-frontend-exporter-options.workspace = true hax-adt-into.workspace = true paste = "1.0.11" diff --git a/frontend/exporter/options/Cargo.toml b/frontend/exporter/options/Cargo.toml deleted file mode 100644 index fadcbc905..000000000 --- a/frontend/exporter/options/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "hax-frontend-exporter-options" -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -edition.workspace = true -repository.workspace = true -readme.workspace = true -description = "The options the `hax-frontend-exporter` crate is sensible to." - -[dependencies] -serde.workspace = true -serde_json.workspace = true -schemars.workspace = true - diff --git a/frontend/exporter/src/lib.rs b/frontend/exporter/src/lib.rs index 610f818e8..e04e88ac9 100644 --- a/frontend/exporter/src/lib.rs +++ b/frontend/exporter/src/lib.rs @@ -48,11 +48,11 @@ cfg_if::cfg_if! { mod body; mod constant_utils; mod index_vec; +pub mod options; mod prelude; mod sinto; mod traits; mod types; pub use hax_adt_into::AdtInto; -pub use hax_frontend_exporter_options as options; pub use prelude::*; diff --git a/frontend/exporter/options/src/lib.rs b/frontend/exporter/src/options.rs similarity index 99% rename from frontend/exporter/options/src/lib.rs rename to frontend/exporter/src/options.rs index a19c79f70..786496f26 100644 --- a/frontend/exporter/options/src/lib.rs +++ b/frontend/exporter/src/options.rs @@ -30,7 +30,7 @@ pub struct Namespace { impl std::convert::From for Namespace { fn from(s: String) -> Self { - Namespace { + Self { chunks: s .split("::") .into_iter() diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index f83248752..c9621a65c 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -231,7 +231,7 @@ pub(crate) fn raw_macro_invocation_of_span<'t, S: BaseState<'t>>( span: rustc_span::Span, state: &S, ) -> Option<(DefId, rustc_span::hygiene::ExpnData)> { - let opts: Rc = state.base().options; + let opts: Rc = state.base().options; let macro_calls: crate::state::MacroCalls = state.base().macro_infos; let sess = state.base().tcx.sess; diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index b805e00c5..c59d07082 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -115,7 +115,7 @@ mod types { #[derive(Clone)] pub struct Base<'tcx> { - pub options: Rc, + pub options: Rc, pub macro_infos: MacroCalls, pub local_ctx: Rc>, pub opt_def_id: Option, @@ -134,10 +134,7 @@ mod types { } impl<'tcx> Base<'tcx> { - pub fn new( - tcx: rustc_middle::ty::TyCtxt<'tcx>, - options: hax_frontend_exporter_options::Options, - ) -> Self { + pub fn new(tcx: rustc_middle::ty::TyCtxt<'tcx>, options: crate::options::Options) -> Self { Self { tcx, macro_infos: Rc::new(HashMap::new()), @@ -172,10 +169,7 @@ mk!( pub use self::types::*; impl<'tcx> State, (), (), ()> { - pub fn new( - tcx: rustc_middle::ty::TyCtxt<'tcx>, - options: hax_frontend_exporter_options::Options, - ) -> Self { + pub fn new(tcx: rustc_middle::ty::TyCtxt<'tcx>, options: crate::options::Options) -> Self { Self { thir: (), mir: (), @@ -198,7 +192,7 @@ impl<'tcx> State, (), (), rustc_hir::def_id::DefId> { impl<'tcx> State, (), Rc>, rustc_hir::def_id::DefId> { pub fn new_from_mir( tcx: rustc_middle::ty::TyCtxt<'tcx>, - options: hax_frontend_exporter_options::Options, + options: crate::options::Options, mir: rustc_middle::mir::Body<'tcx>, owner_id: rustc_hir::def_id::DefId, ) -> Self { diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 106b79078..4ade138b0 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -322,8 +322,8 @@ mod full { } } - #[tracing::instrument(level = "trace", skip(s))] impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] fn impl_expr>( &self, s: &S, From f0dfa77abf833706fe71cb77f1ac0d91923c110d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 13 Jun 2024 16:11:28 +0200 Subject: [PATCH 4/6] fix(gh-actions): stop updating `hax-frontend-exporter-option` --- .github/workflows/charon.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/charon.yml b/.github/workflows/charon.yml index 39351b55d..994eac81d 100644 --- a/.github/workflows/charon.yml +++ b/.github/workflows/charon.yml @@ -12,5 +12,4 @@ jobs: - run: | cd charon cargo update -p hax-frontend-exporter --precise ${{ github.sha }} - cargo update -p hax-frontend-exporter-options --precise ${{ github.sha }} - run: nix build -L From 6b6b5b3c39ea90957112f68d2f7a9fb15c8d0599 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 13 Jun 2024 16:14:43 +0200 Subject: [PATCH 5/6] chore: cargo fmt --- frontend/exporter/src/constant_utils.rs | 82 ++++++++++++------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index a743f7291..bbbca6ad4 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -230,27 +230,27 @@ mod full { // The documentation explicitly says not to match on a scalar. // We match on the type and use it to convert the value. let kind = match ty.kind() { - ty::Char | ty::Bool | ty::Int(_) | ty::Uint(_) => { - let scalar_int = scalar.try_to_int().unwrap_or_else(|_| { - fatal!( - s[span], - "Type is primitive, but the scalar {:#?} is not a [Int]", - scalar - ) - }); - ConstantExprKind::Literal(scalar_int_to_constant_literal(s, scalar_int, ty)) - } - ty::Ref(region, ty, Mutability::Not) if region.is_erased() => { - let tcx = s.base().tcx; - let pointer = scalar.to_pointer(&tcx).unwrap_or_else(|_| { - fatal!( - s[span], - "Type is [Ref], but the scalar {:#?} is not a [Pointer]", - scalar - ) - }); - use rustc_middle::mir::interpret::GlobalAlloc; - let contents = match tcx.global_alloc(pointer.provenance.s_unwrap(s)) { + ty::Char | ty::Bool | ty::Int(_) | ty::Uint(_) => { + let scalar_int = scalar.try_to_int().unwrap_or_else(|_| { + fatal!( + s[span], + "Type is primitive, but the scalar {:#?} is not a [Int]", + scalar + ) + }); + ConstantExprKind::Literal(scalar_int_to_constant_literal(s, scalar_int, ty)) + } + ty::Ref(region, ty, Mutability::Not) if region.is_erased() => { + let tcx = s.base().tcx; + let pointer = scalar.to_pointer(&tcx).unwrap_or_else(|_| { + fatal!( + s[span], + "Type is [Ref], but the scalar {:#?} is not a [Pointer]", + scalar + ) + }); + use rustc_middle::mir::interpret::GlobalAlloc; + let contents = match tcx.global_alloc(pointer.provenance.s_unwrap(s)) { GlobalAlloc::Static(did) => ConstantExprKind::GlobalName { id: did.sinto(s), generics: Vec::new(), trait_refs: Vec::new() }, GlobalAlloc::Memory(alloc) => { let values = alloc.inner().get_bytes_unchecked(rustc_middle::mir::interpret::AllocRange { @@ -265,27 +265,27 @@ mod full { provenance ) }; - ConstantExprKind::Borrow(contents.decorate(ty.sinto(s), cspan.clone())) - } - // A [Scalar] might also be any zero-sized [Adt] or [Tuple] (i.e., unit) - ty::Tuple(ty) if ty.is_empty() => ConstantExprKind::Tuple { fields: vec![] }, - // It seems we can have ADTs when there is only one variant, and this variant doesn't have any fields. - ty::Adt(def, _) - if let [variant_def] = &def.variants().raw - && variant_def.fields.is_empty() => - { - ConstantExprKind::Adt { - info: get_variant_information(def, rustc_abi::FIRST_VARIANT, s), - fields: vec![], + ConstantExprKind::Borrow(contents.decorate(ty.sinto(s), cspan.clone())) } - } - _ => fatal!( - s[span], - "Unexpected type {:#?} for scalar {:#?}", - ty, - scalar - ), - }; + // A [Scalar] might also be any zero-sized [Adt] or [Tuple] (i.e., unit) + ty::Tuple(ty) if ty.is_empty() => ConstantExprKind::Tuple { fields: vec![] }, + // It seems we can have ADTs when there is only one variant, and this variant doesn't have any fields. + ty::Adt(def, _) + if let [variant_def] = &def.variants().raw + && variant_def.fields.is_empty() => + { + ConstantExprKind::Adt { + info: get_variant_information(def, rustc_abi::FIRST_VARIANT, s), + fields: vec![], + } + } + _ => fatal!( + s[span], + "Unexpected type {:#?} for scalar {:#?}", + ty, + scalar + ), + }; kind.decorate(ty.sinto(s), cspan) } From a8a12d8a5bb9d7982e3ca822eb54130ad90501e5 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 13 Jun 2024 17:19:28 +0200 Subject: [PATCH 6/6] wip: does that fix the CI? --- engine/names/extract/build.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 2e4a38511..46dbc1e26 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -142,9 +142,6 @@ fn get_json() -> String { .stderr(Stdio::piped()); cmd.env("CARGO_TARGET_DIR", target_dir("hax")); - for env in ["DYLD_FALLBACK_LIBRARY_PATH", "LD_LIBRARY_PATH"] { - cmd.env_remove(env); - } let out = cmd.output().unwrap(); let stdout = String::from_utf8(out.stdout).unwrap(); let stderr = String::from_utf8(out.stderr).unwrap();