diff --git a/crates/flux-fhir-analysis/src/lib.rs b/crates/flux-fhir-analysis/src/lib.rs index c4db085a8b..1d925ff6b6 100644 --- a/crates/flux-fhir-analysis/src/lib.rs +++ b/crates/flux-fhir-analysis/src/lib.rs @@ -22,9 +22,8 @@ use flux_middle::{ fhir::{self, FluxLocalDefId, WfckResults}, global_env::GlobalEnv, intern::List, - queries::{Providers, QueryErr, QueryResult}, + queries::{Providers, QueryResult}, rty::{self, fold::TypeFoldable, refining::Refiner}, - rustc::lowering, }; use itertools::Itertools; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage}; @@ -143,8 +142,7 @@ fn item_bounds( fn generics_of(genv: &GlobalEnv, local_id: LocalDefId) -> QueryResult { let def_id = local_id.to_def_id(); - let rustc_generics = lowering::lower_generics(genv.tcx.generics_of(def_id)) - .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err))?; + let rustc_generics = genv.lower_generics_of(local_id)?; let def_kind = genv.tcx.def_kind(def_id); match def_kind { diff --git a/crates/flux-middle/locales/en-US.ftl b/crates/flux-middle/locales/en-US.ftl index 011c2c0396..d17d189902 100644 --- a/crates/flux-middle/locales/en-US.ftl +++ b/crates/flux-middle/locales/en-US.ftl @@ -21,6 +21,6 @@ middle_unsupported_generic_bound = # Query Errors -middle_query_unsupported_type = - unsupported type +middle_query_unsupported = + unsupported signature .note = {$reason} diff --git a/crates/flux-middle/src/global_env.rs b/crates/flux-middle/src/global_env.rs index 9702f89361..3ae7f84037 100644 --- a/crates/flux-middle/src/global_env.rs +++ b/crates/flux-middle/src/global_env.rs @@ -88,6 +88,17 @@ impl<'sess, 'tcx> GlobalEnv<'sess, 'tcx> { self.queries.mir(self, def_id) } + pub fn lower_generics_of(&self, def_id: impl Into) -> QueryResult> { + self.queries.lower_generics_of(self, def_id.into()) + } + + pub fn lower_predicates_of( + &self, + def_id: impl Into, + ) -> QueryResult { + self.queries.lower_predicates_of(self, def_id.into()) + } + pub fn lower_type_of(&self, def_id: impl Into) -> QueryResult> { self.queries.lower_type_of(self, def_id.into()) } diff --git a/crates/flux-middle/src/queries.rs b/crates/flux-middle/src/queries.rs index 2e13bc0b5d..9f128067b5 100644 --- a/crates/flux-middle/src/queries.rs +++ b/crates/flux-middle/src/queries.rs @@ -28,7 +28,7 @@ use crate::{ }, rustc::{ self, - lowering::{self, UnsupportedReason}, + lowering::{self, UnsupportedErr, UnsupportedReason}, ty, }, }; @@ -39,7 +39,7 @@ pub type QueryResult = Result; #[derive(Debug, Clone)] pub enum QueryErr { - UnsupportedType { def_id: DefId, def_span: Span, reason: UnsupportedReason }, + Unsupported { def_id: DefId, def_span: Span, err: UnsupportedErr }, Emitted(ErrorGuaranteed), } @@ -89,6 +89,8 @@ impl Default for Providers { pub struct Queries<'tcx> { pub(crate) providers: Providers, mir: Cache>>>, + lower_generics_of: Cache>>, + lower_predicates_of: Cache>, lower_type_of: Cache>>, lower_fn_sig: Cache>>, defns: OnceCell>, @@ -118,6 +120,31 @@ impl<'tcx> Queries<'tcx> { }) } + pub(crate) fn lower_generics_of( + &self, + genv: &GlobalEnv<'_, 'tcx>, + def_id: DefId, + ) -> QueryResult> { + run_with_cache(&self.lower_generics_of, def_id, || { + let generics = genv.tcx.generics_of(def_id); + lowering::lower_generics(generics) + .map_err(UnsupportedReason::to_err) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err)) + }) + } + + pub(crate) fn lower_predicates_of( + &self, + genv: &GlobalEnv, + def_id: DefId, + ) -> QueryResult { + run_with_cache(&self.lower_predicates_of, def_id, || { + let predicates = genv.tcx.predicates_of(def_id); + lowering::lower_generic_predicates(genv.tcx, predicates) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err)) + }) + } + pub(crate) fn lower_type_of( &self, genv: &GlobalEnv, @@ -127,7 +154,8 @@ impl<'tcx> Queries<'tcx> { let ty = genv.tcx.type_of(def_id).instantiate_identity(); Ok(ty::EarlyBinder( lowering::lower_ty(genv.tcx, ty) - .map_err(|reason| QueryErr::unsupported(genv.tcx, def_id, reason))?, + .map_err(UnsupportedReason::to_err) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err))?, )) }) } @@ -148,7 +176,8 @@ impl<'tcx> Queries<'tcx> { .normalize(fn_sig.instantiate_identity()); Ok(ty::EarlyBinder( lowering::lower_fn_sig(genv.tcx, result.value) - .map_err(|reason| QueryErr::unsupported(genv.tcx, def_id, reason))?, + .map_err(UnsupportedReason::to_err) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err))?, )) }) } @@ -209,9 +238,7 @@ impl<'tcx> Queries<'tcx> { if let Some(local_id) = def_id.as_local() { (self.providers.generics_of)(genv, local_id) } else { - let generics = genv.tcx.generics_of(def_id); - let generics = lowering::lower_generics(generics) - .map_err(|reason| QueryErr::unsupported(genv.tcx, def_id, reason))?; + let generics = genv.lower_generics_of(def_id)?; refining::refine_generics(genv, &generics) } }) @@ -228,11 +255,9 @@ impl<'tcx> Queries<'tcx> { if let Some(local_id) = def_id.as_local() { (self.providers.item_bounds)(genv, local_id) } else { - // If there's any error during lowering we blame the span of the definition of - // the opaque type, i.e. the span of the `impl Trait` - let span = genv.tcx.def_span(def_id); let bounds = genv.tcx.item_bounds(def_id).skip_binder(); - let clauses = lowering::lower_item_bounds(genv.tcx, genv.sess, bounds, span)?; + let clauses = lowering::lower_item_bounds(genv.tcx, bounds) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id, err))?; let clauses = Refiner::default(genv, &genv.generics_of(def_id)?).refine_clauses(&clauses)?; @@ -252,10 +277,7 @@ impl<'tcx> Queries<'tcx> { if let Some(local_id) = def_id.as_local() { (self.providers.predicates_of)(genv, local_id) } else { - let predicates = genv.tcx.predicates_of(def_id); - let predicates = - lowering::lower_generic_predicates(genv.tcx, genv.sess, predicates)?; - + let predicates = genv.lower_predicates_of(def_id)?; let predicates = Refiner::default(genv, &genv.generics_of(def_id)?) .refine_generic_predicates(&predicates)?; Ok(rty::EarlyBinder(predicates)) @@ -353,7 +375,8 @@ impl<'tcx> Queries<'tcx> { let hir_id = genv.hir().local_def_id_to_hir_id(def_id); let bound_vars = genv.tcx.late_bound_vars(hir_id); lowering::lower_bound_vars(bound_vars) - .map_err(|reason| QueryErr::unsupported(genv.tcx, def_id.to_def_id(), reason)) + .map_err(UnsupportedReason::to_err) + .map_err(|err| QueryErr::unsupported(genv.tcx, def_id.to_def_id(), err)) }) } } @@ -372,8 +395,8 @@ where } impl QueryErr { - pub fn unsupported(tcx: TyCtxt, def_id: DefId, reason: UnsupportedReason) -> Self { - QueryErr::UnsupportedType { def_id, def_span: tcx.def_span(def_id), reason } + pub fn unsupported(tcx: TyCtxt, def_id: DefId, err: UnsupportedErr) -> Self { + QueryErr::Unsupported { def_id, def_span: tcx.def_span(def_id), err } } } @@ -384,12 +407,14 @@ impl<'a> IntoDiagnostic<'a> for QueryErr { ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { use crate::fluent_generated as fluent; match self { - QueryErr::UnsupportedType { reason, .. } => { - let mut builder = handler.struct_err_with_code( - fluent::middle_query_unsupported_type, + QueryErr::Unsupported { err, def_span, .. } => { + let span = err.span.unwrap_or(def_span); + let mut builder = handler.struct_span_err_with_code( + span, + fluent::middle_query_unsupported, flux_errors::diagnostic_id(), ); - builder.note(reason.descr); + builder.note(err.descr); builder } QueryErr::Emitted(_) => { diff --git a/crates/flux-middle/src/rustc/lowering.rs b/crates/flux-middle/src/rustc/lowering.rs index a0eafaca91..47397838ae 100644 --- a/crates/flux-middle/src/rustc/lowering.rs +++ b/crates/flux-middle/src/rustc/lowering.rs @@ -47,6 +47,33 @@ pub struct UnsupportedReason { pub(crate) descr: String, } +impl UnsupportedReason { + fn new(reason: impl ToString) -> Self { + UnsupportedReason { descr: reason.to_string() } + } + + pub(crate) fn to_err(self) -> UnsupportedErr { + UnsupportedErr { descr: self.descr, span: None } + } +} + +#[derive(Debug, Clone)] +pub struct UnsupportedErr { + pub(crate) descr: String, + pub(crate) span: Option, +} + +impl UnsupportedErr { + fn new(reason: UnsupportedReason) -> Self { + UnsupportedErr { descr: reason.descr, span: None } + } + + fn with_span(mut self, span: Span) -> Self { + self.span = Some(span); + self + } +} + impl<'sess, 'tcx> LoweringCtxt<'_, 'sess, 'tcx> { pub fn lower_mir_body( tcx: TyCtxt<'tcx>, @@ -558,12 +585,6 @@ pub fn lower_place(place: &rustc_mir::Place) -> Result Ok(Place { local: place.local, projection }) } -impl UnsupportedReason { - fn new(reason: impl ToString) -> Self { - UnsupportedReason { descr: reason.to_string() } - } -} - pub(crate) fn lower_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, fn_sig: rustc_ty::PolyFnSig<'tcx>, @@ -752,7 +773,7 @@ fn lower_bound_region( Ok(BoundRegion { kind: bregion.kind, var: bregion.var }) } -pub fn lower_generics(generics: &rustc_ty::Generics) -> Result { +pub(crate) fn lower_generics(generics: &rustc_ty::Generics) -> Result { let params = List::from_vec( generics .params @@ -781,82 +802,62 @@ fn lower_generic_param_def( pub(crate) fn lower_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - sess: &FluxSession, generics: rustc_ty::GenericPredicates<'tcx>, -) -> Result { +) -> Result { let predicates = generics .predicates .iter() - .map(|(clause, span)| lower_clause(tcx, sess, clause, *span)) + .map(|(clause, span)| { + lower_clause(tcx, clause).map_err(|reason| UnsupportedErr::new(reason).with_span(*span)) + }) .try_collect()?; Ok(GenericPredicates { parent: generics.parent, predicates }) } pub(crate) fn lower_item_bounds<'tcx>( tcx: TyCtxt<'tcx>, - sess: &FluxSession, bounds: &[rustc_ty::Clause<'tcx>], - span: Span, -) -> Result, ErrorGuaranteed> { +) -> Result, UnsupportedErr> { bounds .iter() - .map(|clause| lower_clause(tcx, sess, clause, span)) + .map(|clause| lower_clause(tcx, clause).map_err(UnsupportedErr::new)) .try_collect() } fn lower_clause<'tcx>( tcx: TyCtxt<'tcx>, - sess: &FluxSession, clause: &rustc_ty::Clause<'tcx>, - span: Span, -) -> Result { +) -> Result { let Some(kind) = clause.kind().no_bound_vars() else { - return Err(sess.emit_err(errors::UnsupportedGenericBound::new( - span, - "higher-rank trait bounds are not supported", - ))); + return Err(UnsupportedReason::new("higher-rank trait bounds are not supported")); }; let kind = match kind { rustc_ty::ClauseKind::Trait(trait_pred) => { ClauseKind::Trait(TraitPredicate { trait_ref: TraitRef { def_id: trait_pred.trait_ref.def_id, - args: lower_generic_args(tcx, trait_pred.trait_ref.args) - .map_err(|err| errors::UnsupportedGenericBound::new(span, err.descr)) - .emit(sess)?, + args: lower_generic_args(tcx, trait_pred.trait_ref.args)?, }, }) } rustc_ty::ClauseKind::Projection(proj_pred) => { let Some(term) = proj_pred.term.ty() else { - return Err(sess.emit_err(errors::UnsupportedGenericBound::new( - span, - format!("unsupported projection predicate `{proj_pred:?}`"), + return Err(UnsupportedReason::new(format!( + "unsupported projection predicate `{proj_pred:?}`" ))); }; let proj_ty = proj_pred.projection_ty; - let args = lower_generic_args(tcx, proj_ty.args) - .map_err(|err| errors::UnsupportedGenericBound::new(span, err.descr)) - .emit(sess)?; + let args = lower_generic_args(tcx, proj_ty.args)?; let projection_ty = AliasTy { args, def_id: proj_ty.def_id }; - let term = lower_ty(tcx, term) - .map_err(|err| errors::UnsupportedGenericBound::new(span, err.descr)) - .emit(sess)?; + let term = lower_ty(tcx, term)?; ClauseKind::Projection(ProjectionPredicate { projection_ty, term }) } rustc_ty::ClauseKind::TypeOutlives(outlives_pred) => { - ClauseKind::TypeOutlives( - lower_type_outlives(tcx, outlives_pred) - .map_err(|err| errors::UnsupportedGenericBound::new(span, err.descr)) - .emit(sess)?, - ) + ClauseKind::TypeOutlives(lower_type_outlives(tcx, outlives_pred)?) } _ => { - return Err(sess.emit_err(errors::UnsupportedGenericBound::new( - span, - format!("unsupported clause kind `{kind:?}`"), - ))); + return Err(UnsupportedReason::new(format!("unsupported clause kind `{kind:?}`"))); } }; Ok(Clause::new(kind)) @@ -941,19 +942,4 @@ mod errors { ) } } - - #[derive(Diagnostic)] - #[diag(middle_unsupported_generic_bound, code = "FLUX")] - #[note] - pub struct UnsupportedGenericBound { - #[primary_span] - span: Span, - reason: String, - } - - impl UnsupportedGenericBound { - pub fn new(span: Span, reason: impl ToString) -> Self { - Self { span, reason: reason.to_string() } - } - } } diff --git a/crates/flux-middle/src/rustc/ty.rs b/crates/flux-middle/src/rustc/ty.rs index cf9f71c5d1..58bab868c1 100644 --- a/crates/flux-middle/src/rustc/ty.rs +++ b/crates/flux-middle/src/rustc/ty.rs @@ -26,6 +26,7 @@ use crate::{ pretty::def_id_to_string, }; +#[derive(Clone)] pub struct Generics<'tcx> { pub params: List, pub orig: &'tcx rustc_middle::ty::Generics, @@ -57,7 +58,7 @@ pub enum GenericParamDefKind { Const { has_default: bool }, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct GenericPredicates { pub parent: Option, pub predicates: List,