diff --git a/cargo-marker/src/driver.rs b/cargo-marker/src/driver.rs index be66cace..da34d002 100644 --- a/cargo-marker/src/driver.rs +++ b/cargo-marker/src/driver.rs @@ -41,7 +41,7 @@ pub fn print_driver_version() { } /// This tries to install the rustc driver specified in [`DEFAULT_DRIVER_INFO`]. -pub fn install_driver(verbose: bool) -> Result<(), ExitStatus> { +pub fn install_driver(verbose: bool, dev_build: bool) -> Result<(), ExitStatus> { // The toolchain, driver version and api version should ideally be configurable. // However, that will require more prototyping and has a low priority rn. // See #60 @@ -50,12 +50,7 @@ pub fn install_driver(verbose: bool) -> Result<(), ExitStatus> { let toolchain = &DEFAULT_DRIVER_INFO.toolchain; check_toolchain(toolchain)?; - build_driver( - toolchain, - &DEFAULT_DRIVER_INFO.version, - verbose, - cfg!(feature = "dev-build"), - )?; + build_driver(toolchain, &DEFAULT_DRIVER_INFO.version, verbose, dev_build)?; // We don't want to advice the user, to install the driver again. check_driver(verbose, false) diff --git a/cargo-marker/src/main.rs b/cargo-marker/src/main.rs index 51db32f5..0a38c02c 100644 --- a/cargo-marker/src/main.rs +++ b/cargo-marker/src/main.rs @@ -78,6 +78,7 @@ fn main() -> Result<(), ExitStatus> { ); let verbose = matches.get_flag("verbose"); + let dev_build = cfg!(feature = "dev-build"); if matches.get_flag("version") { print_version(verbose); @@ -85,14 +86,19 @@ fn main() -> Result<(), ExitStatus> { } match matches.subcommand() { - Some(("setup", _args)) => driver::install_driver(verbose), - Some(("check", args)) => run_check(args, verbose), - None => run_check(&matches, verbose), + Some(("setup", _args)) => driver::install_driver(verbose, dev_build), + Some(("check", args)) => run_check(args, verbose, dev_build), + None => run_check(&matches, verbose, dev_build), _ => unreachable!(), } } -fn run_check(matches: &clap::ArgMatches, verbose: bool) -> Result<(), ExitStatus> { +fn run_check(matches: &clap::ArgMatches, verbose: bool, dev_build: bool) -> Result<(), ExitStatus> { + // If this is a dev build, we want to recompile the driver before checking + if dev_build { + driver::install_driver(verbose, dev_build)?; + } + let mut lint_crates = vec![]; if let Some(cmd_lint_crates) = matches.get_many::("lints") { println!(); diff --git a/marker_driver_rustc/src/conversion/generic.rs b/marker_driver_rustc/src/conversion/generic.rs index 96611b2c..e1b54a8d 100644 --- a/marker_driver_rustc/src/conversion/generic.rs +++ b/marker_driver_rustc/src/conversion/generic.rs @@ -2,13 +2,42 @@ use marker_api::ast::{ generic::{BindingGenericArg, GenericArgKind, GenericArgs, Lifetime, LifetimeKind, TraitBound, TyParamBound}, TraitRef, }; +use rustc_hir as hir; use crate::context::RustcContext; use super::{to_generic_id, to_item_id, to_span_id, to_symbol_id, ty::TyConverter}; -pub fn to_api_lifetime<'ast>( - _cx: &'ast RustcContext<'ast, '_>, +pub fn conv_ast_bound<'ast, 'tcx>( + cx: &'ast RustcContext<'ast, 'tcx>, + bounds: &'tcx [hir::GenericBound], +) -> &'ast [TyParamBound<'ast>] { + if bounds.is_empty() { + return &[]; + } + + let bounds: Vec<_> = bounds + .iter() + .filter_map(|bound| match bound { + hir::GenericBound::Trait(trait_ref, modifier) => Some(TyParamBound::TraitBound(cx.storage.alloc(|| { + TraitBound::new( + !matches!(modifier, hir::TraitBoundModifier::None), + to_api_trait_ref(cx, &trait_ref.trait_ref), + to_span_id(bound.span()), + ) + }))), + hir::GenericBound::LangItemTrait(_, _, _, _) => todo!(), + hir::GenericBound::Outlives(rust_lt) => { + to_api_lifetime(cx, rust_lt).map(|api_lt| TyParamBound::Lifetime(cx.storage.alloc(|| api_lt))) + }, + }) + .collect(); + + cx.storage.alloc_slice_iter(bounds.into_iter()) +} + +pub fn to_api_lifetime<'ast, 'tcx>( + _cx: &'ast RustcContext<'ast, 'tcx>, rust_lt: &rustc_hir::Lifetime, ) -> Option> { let kind = match rust_lt.res { diff --git a/marker_driver_rustc/src/conversion/item.rs b/marker_driver_rustc/src/conversion/item.rs index 35d0f839..48f2e8fb 100644 --- a/marker_driver_rustc/src/conversion/item.rs +++ b/marker_driver_rustc/src/conversion/item.rs @@ -1,8 +1,5 @@ use marker_api::ast::{ - generic::{ - GenericParamKind, GenericParams, LifetimeClause, LifetimeParam, TraitBound, TyClause, TyParam, TyParamBound, - WhereClauseKind, - }, + generic::{GenericParamKind, GenericParams, LifetimeClause, LifetimeParam, TyClause, TyParam, WhereClauseKind}, item::{ AdtKind, AssocItemKind, CommonItemData, ConstItem, EnumItem, EnumVariant, ExternBlockItem, ExternCrateItem, ExternItemKind, Field, FnItem, ImplItem, ItemKind, ModItem, StaticItem, StructItem, TraitItem, TyAliasItem, @@ -16,7 +13,7 @@ use rustc_hir as hir; use crate::context::RustcContext; use super::{ - generic::{to_api_lifetime, to_api_trait_ref}, + generic::{conv_ast_bound, to_api_lifetime, to_api_trait_ref}, to_api_abi, to_api_body_id, to_api_path, to_generic_id, to_item_id, to_rustc_item_id, to_span_id, to_symbol_id, ty::TyConverter, }; @@ -115,7 +112,7 @@ impl<'ast, 'tcx> ItemConverter<'ast, 'tcx> { data, matches!(unsafety, hir::Unsafety::Unsafe), self.conv_generic(generics), - self.conv_generic_bounds(bounds), + conv_ast_bound(self.cx, bounds), self.conv_trait_items(items), ) })), @@ -219,7 +216,7 @@ impl<'ast, 'tcx> ItemConverter<'ast, 'tcx> { TyAliasItem::new( data, self.conv_generic(trait_item.generics), - self.conv_generic_bounds(bounds), + conv_ast_bound(self.cx, bounds), ty.map(|ty| self.conv_ty(ty)), ) })), @@ -310,31 +307,6 @@ impl<'ast, 'tcx> ItemConverter<'ast, 'tcx> { self.cx.storage.alloc_slice_iter(params.into_iter()) } - fn conv_generic_bounds(&self, bounds: hir::GenericBounds<'tcx>) -> &'ast [TyParamBound<'ast>] { - if bounds.is_empty() { - return &[]; - } - - let bounds: Vec<_> = bounds - .iter() - .filter_map(|bound| match bound { - hir::GenericBound::Trait(trait_ref, modifier) => Some(TyParamBound::TraitBound(self.alloc(|| { - TraitBound::new( - !matches!(modifier, hir::TraitBoundModifier::None), - to_api_trait_ref(self.cx, &trait_ref.trait_ref), - to_span_id(bound.span()), - ) - }))), - hir::GenericBound::LangItemTrait(_, _, _, _) => todo!(), - hir::GenericBound::Outlives(rust_lt) => { - to_api_lifetime(self.cx, rust_lt).map(|api_lt| TyParamBound::Lifetime(self.alloc(|| api_lt))) - }, - }) - .collect(); - - self.cx.storage.alloc_slice_iter(bounds.into_iter()) - } - fn conv_generic(&self, rustc_generics: &hir::Generics<'tcx>) -> GenericParams<'ast> { // FIXME: Update implementation to store the parameter bounds in the parameters let clauses: Vec<_> = rustc_generics @@ -348,7 +320,7 @@ impl<'ast, 'tcx> ItemConverter<'ast, 'tcx> { let params = GenericParams::new(self.conv_generic_params(ty_bound.bound_generic_params), &[]); let ty = self.conv_ty(ty_bound.bounded_ty); Some(WhereClauseKind::Ty(self.alloc(|| { - TyClause::new(Some(params), ty, self.conv_generic_bounds(predicate.bounds())) + TyClause::new(Some(params), ty, conv_ast_bound(self.cx, predicate.bounds())) }))) }, hir::WherePredicate::RegionPredicate(lifetime_bound) => { diff --git a/marker_driver_rustc/src/conversion/ty.rs b/marker_driver_rustc/src/conversion/ty.rs index 9f748f75..2fbfdc6d 100644 --- a/marker_driver_rustc/src/conversion/ty.rs +++ b/marker_driver_rustc/src/conversion/ty.rs @@ -1,7 +1,8 @@ use marker_api::ast::{ ty::{ - AliasTy, ArrayTy, BoolTy, CommonTyData, EnumTy, FnTy, GenericTy, InferredTy, NeverTy, NumKind, NumTy, RawPtrTy, - RefTy, RelativeTy, SelfTy, SliceTy, StructTy, TextKind, TextTy, TraitObjTy, TupleTy, TyKind, UnionTy, + AliasTy, ArrayTy, BoolTy, CommonTyData, EnumTy, FnTy, GenericTy, ImplTraitTy, InferredTy, NeverTy, NumKind, + NumTy, RawPtrTy, RefTy, RelativeTy, SelfTy, SliceTy, StructTy, TextKind, TextTy, TraitObjTy, TupleTy, TyKind, + UnionTy, }, CommonCallableData, Parameter, }; @@ -12,7 +13,7 @@ use crate::{ }; use super::{ - generic::{to_api_generic_args, to_api_lifetime, to_api_trait_bounds_from_hir}, + generic::{conv_ast_bound, to_api_generic_args, to_api_lifetime, to_api_trait_bounds_from_hir}, to_generic_id, to_item_id, to_span_id, to_ty_def_id, }; @@ -82,10 +83,15 @@ impl<'ast, 'tcx> TyConverter<'ast, 'tcx> { TyKind::Tuple(self.cx.storage.alloc(|| TupleTy::new(data, api_tys))) }, hir::TyKind::Path(qpath) => self.conv_syn_qpath(data, qpath), - hir::TyKind::OpaqueDef(_, _, _) => { - // This requires function items to be implemented. Therefore we'll leave this as an open TODO for - // now - todo!("{:#?}", rustc_ty) + hir::TyKind::OpaqueDef(id, _, _) => { + // `impl Trait` in rustc are implemented as Items with the kind `OpaqueTy` + let item = self.cx.rustc_cx.hir().item(*id); + let hir::ItemKind::OpaqueTy(opty) = &item.kind else { + unreachable!("the item of a `OpaqueDef` should be `OpaqueTy` {item:#?}"); + }; + let rust_bound = conv_ast_bound(self.cx, opty.bounds); + // FIXME: Generics are a bit weird with opaque types + TyKind::ImplTrait(self.cx.storage.alloc(|| ImplTraitTy::new(data, rust_bound))) }, hir::TyKind::TraitObject(rust_bounds, rust_lt, _syntax) => TyKind::TraitObj( self.cx