diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
4 files changed, 242 insertions, 2 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 216b89fd4f1..8c85d13650b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,10 +1,10 @@ use crate::check::intrinsicck::InlineAsmCtxt; -use crate::errors::LinkageType; use super::compare_impl_item::check_type_bounds; use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::*; use rustc_attr as attr; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{codes::*, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; @@ -12,6 +12,7 @@ use rustc_hir::Node; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; +use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::fold::BottomUpFolder; @@ -474,6 +475,133 @@ fn sanity_check_found_hidden_type<'tcx>( } } +/// Check that the opaque's precise captures list is valid (if present). +/// We check this for regular `impl Trait`s and also RPITITs, even though the latter +/// are technically GATs. +/// +/// This function is responsible for: +/// 1. Checking that all type/const params are mention in the captures list. +/// 2. Checking that all lifetimes that are implicitly captured are mentioned. +/// 3. Asserting that all parameters mentioned in the captures list are invariant. +fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { + let hir::OpaqueTy { precise_capturing_args, .. } = + *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let Some(precise_capturing_args) = precise_capturing_args else { + // No precise capturing args; nothing to validate + return; + }; + + let mut expected_captures = UnordSet::default(); + let mut seen_params = UnordMap::default(); + let mut prev_non_lifetime_param = None; + for arg in precise_capturing_args { + let (hir_id, ident) = match *arg { + hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg { + hir_id, + ident, + .. + }) => { + if prev_non_lifetime_param.is_none() { + prev_non_lifetime_param = Some(ident); + } + (hir_id, ident) + } + hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => { + if let Some(prev_non_lifetime_param) = prev_non_lifetime_param { + tcx.dcx().emit_err(errors::LifetimesMustBeFirst { + lifetime_span: ident.span, + name: ident.name, + other_span: prev_non_lifetime_param.span, + }); + } + (hir_id, ident) + } + }; + + let ident = ident.normalize_to_macros_2_0(); + if let Some(span) = seen_params.insert(ident, ident.span) { + tcx.dcx().emit_err(errors::DuplicatePreciseCapture { + name: ident.name, + first_span: span, + second_span: ident.span, + }); + } + + match tcx.named_bound_var(hir_id) { + Some(ResolvedArg::EarlyBound(def_id)) => { + expected_captures.insert(def_id); + } + _ => { + tcx.dcx().span_delayed_bug( + tcx.hir().span(hir_id), + "parameter should have been resolved", + ); + } + } + } + + let variances = tcx.variances_of(opaque_def_id); + let mut def_id = Some(opaque_def_id.to_def_id()); + while let Some(generics) = def_id { + let generics = tcx.generics_of(generics); + def_id = generics.parent; + + for param in &generics.params { + if expected_captures.contains(¶m.def_id) { + assert_eq!( + variances[param.index as usize], + ty::Invariant, + "precise captured param should be invariant" + ); + continue; + } + + match param.kind { + ty::GenericParamDefKind::Lifetime => { + // Check if the lifetime param was captured but isn't named in the precise captures list. + if variances[param.index as usize] == ty::Invariant { + let param_span = + if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) + | ty::ReLateParam(ty::LateParamRegion { + bound_region: ty::BoundRegionKind::BrNamed(def_id, _), + .. + }) = *tcx + .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()) + { + Some(tcx.def_span(def_id)) + } else { + None + }; + // FIXME(precise_capturing): Structured suggestion for this would be useful + tcx.dcx().emit_err(errors::LifetimeNotCaptured { + use_span: tcx.def_span(param.def_id), + param_span, + opaque_span: tcx.def_span(opaque_def_id), + }); + continue; + } + } + ty::GenericParamDefKind::Type { .. } => { + // FIXME(precise_capturing): Structured suggestion for this would be useful + tcx.dcx().emit_err(errors::ParamNotCaptured { + param_span: tcx.def_span(param.def_id), + opaque_span: tcx.def_span(opaque_def_id), + kind: "type", + }); + } + ty::GenericParamDefKind::Const { .. } => { + // FIXME(precise_capturing): Structured suggestion for this would be useful + tcx.dcx().emit_err(errors::ParamNotCaptured { + param_span: tcx.def_span(param.def_id), + opaque_span: tcx.def_span(opaque_def_id), + kind: "const", + }); + } + } + } + } +} + fn is_enum_of_nonnullable_ptr<'tcx>( tcx: TyCtxt<'tcx>, adt_def: AdtDef<'tcx>, @@ -499,7 +627,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args), _ => true, } { - tcx.dcx().emit_err(LinkageType { span: tcx.def_span(def_id) }); + tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) }); } } } @@ -566,6 +694,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_union(tcx, def_id); } DefKind::OpaqueTy => { + check_opaque_precise_captures(tcx, def_id); + let origin = tcx.opaque_type_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3d16f1420d9..78c2665fd1f 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -557,6 +557,50 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } + fn visit_precise_capturing_arg( + &mut self, + arg: &'tcx hir::PreciseCapturingArg<'tcx>, + ) -> Self::Result { + match *arg { + hir::PreciseCapturingArg::Lifetime(lt) => match lt.res { + LifetimeName::Param(def_id) => { + self.resolve_lifetime_ref(def_id, lt); + } + LifetimeName::Error => {} + LifetimeName::ImplicitObjectLifetimeDefault + | LifetimeName::Infer + | LifetimeName::Static => { + self.tcx.dcx().emit_err(errors::BadPreciseCapture { + span: lt.ident.span, + kind: "lifetime", + found: format!("`{}`", lt.ident.name), + }); + } + }, + hir::PreciseCapturingArg::Param(param) => match param.res { + Res::Def(DefKind::TyParam | DefKind::ConstParam, def_id) + | Res::SelfTyParam { trait_: def_id } => { + self.resolve_type_ref(def_id.expect_local(), param.hir_id); + } + Res::Err => {} + Res::SelfTyAlias { alias_to, .. } => { + self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias { + span: param.ident.span, + self_span: self.tcx.def_span(alias_to), + what: self.tcx.def_descr(alias_to), + }); + } + res => { + self.tcx.dcx().emit_err(errors::BadPreciseCapture { + span: param.ident.span, + kind: "type or const", + found: res.descr().to_string(), + }); + } + }, + } + } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(_, _, generics) => { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index d129614e0e1..867ee772a30 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -10,6 +10,9 @@ use rustc_span::{symbol::Ident, Span, Symbol}; mod pattern_types; pub use pattern_types::*; +mod precise_captures; +pub(crate) use precise_captures::*; + #[derive(Diagnostic)] #[diag(hir_analysis_ambiguous_assoc_item)] pub struct AmbiguousAssocItem<'a> { diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs new file mode 100644 index 00000000000..520bf1d9f40 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -0,0 +1,63 @@ +use rustc_macros::Diagnostic; +use rustc_span::{Span, Symbol}; + +#[derive(Diagnostic)] +#[diag(hir_analysis_param_not_captured)] +#[note] +pub struct ParamNotCaptured { + #[primary_span] + pub param_span: Span, + #[label] + pub opaque_span: Span, + pub kind: &'static str, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_lifetime_not_captured)] +pub struct LifetimeNotCaptured { + #[primary_span] + pub use_span: Span, + #[label(hir_analysis_param_label)] + pub param_span: Option<Span>, + #[label] + pub opaque_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_bad_precise_capture)] +pub struct BadPreciseCapture { + #[primary_span] + pub span: Span, + pub kind: &'static str, + pub found: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_precise_capture_self_alias)] +pub struct PreciseCaptureSelfAlias { + #[primary_span] + pub span: Span, + #[label] + pub self_span: Span, + pub what: &'static str, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_duplicate_precise_capture)] +pub struct DuplicatePreciseCapture { + #[primary_span] + pub first_span: Span, + pub name: Symbol, + #[label] + pub second_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_lifetime_must_be_first)] +pub struct LifetimesMustBeFirst { + #[primary_span] + pub lifetime_span: Span, + pub name: Symbol, + #[label] + pub other_span: Span, +} |
