mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #153217 - JonathanBrouwer:rollup-iXVG70B, r=JonathanBrouwer
Rollup of 12 pull requests Successful merges: - rust-lang/rust#153211 (`rust-analyzer` subtree update) - rust-lang/rust#149027 (Improve cross-crate trait impl param mismatch suggestions ) - rust-lang/rust#152730 (add field representing types) - rust-lang/rust#153136 (Correctly handle `#[doc(alias = "...")]` attribute on inlined reexports) - rust-lang/rust#152165 (Normalize capture place `ty`s to prevent ICE) - rust-lang/rust#152615 (refactor 'valid for read/write' definition: exclude null) - rust-lang/rust#153109 (Fix LegacyKeyValueFormat report from docker build: aarch64-gnu-debug) - rust-lang/rust#153172 (Fix comment about placeholders) - rust-lang/rust#153187 (Fix ICE when macro-expanded extern crate shadows std) - rust-lang/rust#153190 (Don't allow subdiagnostic to use variables from their parent) - rust-lang/rust#153200 (Remove redundant clone) - rust-lang/rust#153216 (mark two polonius tests as known-bug)
This commit is contained in:
@@ -4706,6 +4706,7 @@ dependencies = [
|
||||
"ena",
|
||||
"indexmap",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc_abi",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
|
||||
@@ -21,7 +21,64 @@
|
||||
mod ty;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use ty::{Layout, TyAbiInterface, TyAndLayout};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a field in a variant.
|
||||
///
|
||||
/// This is how most code after type checking refers to fields, rather than
|
||||
/// using names (as names have hygiene complications and more complex lookup).
|
||||
///
|
||||
/// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
|
||||
/// (It is for `repr(C)` `struct`s, however.)
|
||||
///
|
||||
/// For example, in the following types,
|
||||
/// ```rust
|
||||
/// # enum Never {}
|
||||
/// # #[repr(u16)]
|
||||
/// enum Demo1 {
|
||||
/// Variant0 { a: Never, b: i32 } = 100,
|
||||
/// Variant1 { c: u8, d: u64 } = 10,
|
||||
/// }
|
||||
/// struct Demo2 { e: u8, f: u16, g: u8 }
|
||||
/// ```
|
||||
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
|
||||
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
|
||||
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
pub struct FieldIdx {}
|
||||
}
|
||||
|
||||
impl FieldIdx {
|
||||
/// The second field, at index 1.
|
||||
///
|
||||
/// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
|
||||
pub const ONE: FieldIdx = FieldIdx::from_u32(1);
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a variant in a type.
|
||||
///
|
||||
/// For enums, these are always `0..variant_count`, regardless of any
|
||||
/// custom discriminants that may have been defined, and including any
|
||||
/// variants that may end up uninhabited due to field types. (Some of the
|
||||
/// variants may not be present in a monomorphized ABI [`Variants`], but
|
||||
/// those skipped variants are always counted when determining the *index*.)
|
||||
///
|
||||
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
|
||||
/// with variant index zero, aka [`FIRST_VARIANT`].
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
pub struct VariantIdx {
|
||||
/// Equivalent to `VariantIdx(0)`.
|
||||
const FIRST_VARIANT = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||
// Present uninhabited variants only require space for their fields,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::layout::{FieldIdx, VariantIdx};
|
||||
use crate::{
|
||||
AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
|
||||
PointeeInfo, Primitive, Size, Variants,
|
||||
@@ -11,60 +12,6 @@
|
||||
|
||||
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a field in a variant.
|
||||
///
|
||||
/// This is how most code after type checking refers to fields, rather than
|
||||
/// using names (as names have hygiene complications and more complex lookup).
|
||||
///
|
||||
/// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
|
||||
/// (It is for `repr(C)` `struct`s, however.)
|
||||
///
|
||||
/// For example, in the following types,
|
||||
/// ```rust
|
||||
/// # enum Never {}
|
||||
/// # #[repr(u16)]
|
||||
/// enum Demo1 {
|
||||
/// Variant0 { a: Never, b: i32 } = 100,
|
||||
/// Variant1 { c: u8, d: u64 } = 10,
|
||||
/// }
|
||||
/// struct Demo2 { e: u8, f: u16, g: u8 }
|
||||
/// ```
|
||||
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
|
||||
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
|
||||
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
|
||||
#[derive(HashStable_Generic)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
pub struct FieldIdx {}
|
||||
}
|
||||
|
||||
impl FieldIdx {
|
||||
/// The second field, at index 1.
|
||||
///
|
||||
/// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
|
||||
pub const ONE: FieldIdx = FieldIdx::from_u32(1);
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// The *source-order* index of a variant in a type.
|
||||
///
|
||||
/// For enums, these are always `0..variant_count`, regardless of any
|
||||
/// custom discriminants that may have been defined, and including any
|
||||
/// variants that may end up uninhabited due to field types. (Some of the
|
||||
/// variants may not be present in a monomorphized ABI [`Variants`], but
|
||||
/// those skipped variants are always counted when determining the *index*.)
|
||||
///
|
||||
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
|
||||
/// with variant index zero, aka [`FIRST_VARIANT`].
|
||||
#[derive(HashStable_Generic)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
pub struct VariantIdx {
|
||||
/// Equivalent to `VariantIdx(0)`.
|
||||
const FIRST_VARIANT = 0;
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
|
||||
|
||||
@@ -64,9 +64,9 @@
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use extern_abi::CVariadicStatus;
|
||||
pub use extern_abi::{ExternAbi, all_names};
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, LayoutCalculator, LayoutCalculatorError, VariantIdx};
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
pub use layout::{Layout, TyAbiInterface, TyAndLayout};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
||||
@@ -2553,6 +2553,11 @@ pub enum TyKind {
|
||||
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`,
|
||||
/// just as part of the type system.
|
||||
Pat(Box<Ty>, Box<TyPat>),
|
||||
/// A `field_of` expression (e.g., `builtin # field_of(Struct, field)`).
|
||||
///
|
||||
/// Usually not written directly in user code but indirectly via the macro
|
||||
/// `core::field::field_of!(...)`.
|
||||
FieldOf(Box<Ty>, Option<Ident>, Ident),
|
||||
/// Sometimes we need a dummy value when no error has occurred.
|
||||
Dummy,
|
||||
/// Placeholder for a kind that has failed to be defined.
|
||||
|
||||
@@ -298,6 +298,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||
| ast::TyKind::ImplicitSelf
|
||||
| ast::TyKind::CVarArgs
|
||||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::FieldOf(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
}
|
||||
|
||||
@@ -1496,6 +1496,13 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
|
||||
TyKind::Pat(ty, pat) => {
|
||||
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
|
||||
}
|
||||
TyKind::FieldOf(ty, variant, field) => hir::TyKind::FieldOf(
|
||||
self.lower_ty_alloc(ty, itctx),
|
||||
self.arena.alloc(hir::TyFieldPath {
|
||||
variant: variant.map(|variant| self.lower_ident(variant)),
|
||||
field: self.lower_ident(*field),
|
||||
}),
|
||||
),
|
||||
TyKind::MacCall(_) => {
|
||||
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
|
||||
}
|
||||
|
||||
@@ -1377,6 +1377,23 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
|
||||
self.word(" is ");
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
ast::TyKind::FieldOf(ty, variant, field) => {
|
||||
self.word("builtin # field_of");
|
||||
self.popen();
|
||||
let ib = self.ibox(0);
|
||||
self.print_type(ty);
|
||||
self.word(",");
|
||||
self.space();
|
||||
|
||||
if let Some(variant) = variant {
|
||||
self.print_ident(*variant);
|
||||
self.word(".");
|
||||
}
|
||||
self.print_ident(*field);
|
||||
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
use rustc_middle::mir::interpret::ReportedErrorInfo;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_middle::ty::{self, FieldInfo, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use tracing::debug;
|
||||
@@ -23,8 +23,9 @@
|
||||
use crate::interpret::{
|
||||
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
|
||||
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format, type_implements_dyn_trait,
|
||||
compile_time_machine, ensure_monomorphic_enough, err_inval, interp_ok, throw_exhaust,
|
||||
throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
type_implements_dyn_trait,
|
||||
};
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
@@ -619,6 +620,27 @@ fn call_intrinsic(
|
||||
ecx.write_type_info(ty, dest)?;
|
||||
}
|
||||
|
||||
sym::field_offset => {
|
||||
let frt_ty = instance.args.type_at(0);
|
||||
ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?;
|
||||
|
||||
let (ty, variant, field) = if let ty::Adt(def, args) = frt_ty.kind()
|
||||
&& let Some(FieldInfo { base, variant_idx, field_idx, .. }) =
|
||||
def.field_representing_type_info(ecx.tcx.tcx, args)
|
||||
{
|
||||
(base, variant_idx, field_idx)
|
||||
} else {
|
||||
span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}")
|
||||
};
|
||||
let layout = ecx.layout_of(ty)?;
|
||||
let cx = ty::layout::LayoutCx::new(ecx.tcx.tcx, ecx.typing_env());
|
||||
|
||||
let layout = layout.for_variant(&cx, variant);
|
||||
let offset = layout.fields.offset(field.index()).bytes();
|
||||
|
||||
ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
// We haven't handled the intrinsic, let's see if we can use a fallback body.
|
||||
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
pub use self::projection::{OffsetMode, Projectable};
|
||||
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation};
|
||||
pub use self::util::EnteredTraceSpan;
|
||||
pub(crate) use self::util::{create_static_alloc, type_implements_dyn_trait};
|
||||
pub(crate) use self::util::{
|
||||
create_static_alloc, ensure_monomorphic_enough, type_implements_dyn_trait,
|
||||
};
|
||||
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
||||
pub use self::visitor::ValueVisitor;
|
||||
|
||||
@@ -221,6 +221,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementable items
|
||||
(internal, eii_internals, "1.94.0", None),
|
||||
/// Implementation details of field representing types.
|
||||
(internal, field_representing_type_raw, "CURRENT_RUSTC_VERSION", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
@@ -486,6 +488,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, ffi_const, "1.45.0", Some(58328)),
|
||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
||||
/// Experimental field projections.
|
||||
(incomplete, field_projections, "CURRENT_RUSTC_VERSION", Some(145383)),
|
||||
/// Allows marking trait functions as `final` to prevent overriding impls
|
||||
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(131179)),
|
||||
/// Controlling the behavior of fmt::Debug
|
||||
|
||||
@@ -1741,6 +1741,12 @@ pub fn innermost_block(&self) -> &Block<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TyFieldPath {
|
||||
pub variant: Option<Ident>,
|
||||
pub field: Ident,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TyPat<'hir> {
|
||||
#[stable_hasher(ignore)]
|
||||
@@ -3804,6 +3810,10 @@ pub enum TyKind<'hir, Unambig = ()> {
|
||||
Err(rustc_span::ErrorGuaranteed),
|
||||
/// Pattern types (`pattern_type!(u32 is 1..)`)
|
||||
Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>),
|
||||
/// Field representing type (`field_of!(Struct, field)`).
|
||||
///
|
||||
/// The optional ident is the variant when an enum is passed `field_of!(Enum, Variant.field)`.
|
||||
FieldOf(&'hir Ty<'hir>, &'hir TyFieldPath),
|
||||
/// `TyKind::Infer` means the type should be inferred instead of it having been
|
||||
/// specified. This can appear anywhere in a type.
|
||||
///
|
||||
|
||||
@@ -1047,6 +1047,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
try_visit!(visitor.visit_pattern_type_pattern(pat));
|
||||
}
|
||||
TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
visit_opt!(visitor, visit_ident, *variant);
|
||||
try_visit!(visitor.visit_ident(*field));
|
||||
}
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
@@ -435,6 +435,13 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
|
||||
// Reborrowing related lang-items
|
||||
Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0);
|
||||
CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
// Field representing types.
|
||||
FieldRepresentingType, sym::field_representing_type, field_representing_type, Target::Struct, GenericRequirement::Exact(3);
|
||||
Field, sym::field, field, Target::Trait, GenericRequirement::Exact(0);
|
||||
FieldBase, sym::field_base, field_base, Target::AssocTy, GenericRequirement::Exact(0);
|
||||
FieldType, sym::field_type, field_type, Target::AssocTy, GenericRequirement::Exact(0);
|
||||
FieldOffset, sym::field_offset, field_offset, Target::AssocConst, GenericRequirement::Exact(0);
|
||||
}
|
||||
|
||||
/// The requirement imposed on the generics of a lang item
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use core::ops::ControlFlow;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
|
||||
use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||
@@ -18,7 +19,7 @@
|
||||
Upcast,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
@@ -1795,6 +1796,105 @@ fn compare_number_of_method_arguments<'tcx>(
|
||||
),
|
||||
);
|
||||
|
||||
// Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).
|
||||
if !trait_m.def_id.is_local() {
|
||||
let trait_sig = tcx.fn_sig(trait_m.def_id);
|
||||
let trait_arg_idents = tcx.fn_arg_idents(trait_m.def_id);
|
||||
let sm = tcx.sess.source_map();
|
||||
// Find the span of the space between the parentheses in a method.
|
||||
// fn foo(...) {}
|
||||
// ^^^
|
||||
let impl_inputs_span = if let (Some(first), Some(last)) =
|
||||
(impl_m_sig.decl.inputs.first(), impl_m_sig.decl.inputs.last())
|
||||
{
|
||||
// We have inputs; construct the span from those.
|
||||
// fn foo( a: i32, b: u32 ) {}
|
||||
// ^^^^^^^^^^^^^^^^
|
||||
let arg_idents = tcx.fn_arg_idents(impl_m.def_id);
|
||||
let first_lo = arg_idents
|
||||
.get(0)
|
||||
.and_then(|id| id.map(|id| id.span.lo()))
|
||||
.unwrap_or(first.span.lo());
|
||||
Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.span.hi()))
|
||||
} else {
|
||||
// We have no inputs; construct the span to the left of the last parenthesis
|
||||
// fn foo( ) {}
|
||||
// ^
|
||||
// FIXME: Keep spans for function parentheses around to make this more robust.
|
||||
sm.span_to_snippet(impl_m_sig.span).ok().and_then(|s| {
|
||||
let right_paren = s.as_bytes().iter().rposition(|&b| b == b')')?;
|
||||
let pos = impl_m_sig.span.lo() + BytePos(right_paren as u32);
|
||||
Some(impl_m_sig.span.with_lo(pos).with_hi(pos))
|
||||
})
|
||||
};
|
||||
let suggestion = match trait_number_args.cmp(&impl_number_args) {
|
||||
Ordering::Greater => {
|
||||
// Span is right before the end parenthesis:
|
||||
// fn foo(a: i32 ) {}
|
||||
// ^
|
||||
let trait_inputs = trait_sig.skip_binder().inputs().skip_binder();
|
||||
let missing = trait_inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(impl_number_args)
|
||||
.map(|(idx, ty)| {
|
||||
let name = trait_arg_idents
|
||||
.get(idx)
|
||||
.and_then(|ident| *ident)
|
||||
.map(|ident| ident.to_string())
|
||||
.unwrap_or_else(|| "_".to_string());
|
||||
format!("{name}: {ty}")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if missing.is_empty() {
|
||||
None
|
||||
} else {
|
||||
impl_inputs_span.map(|s| {
|
||||
let span = s.shrink_to_hi();
|
||||
let prefix = if impl_number_args == 0 { "" } else { ", " };
|
||||
let replacement = format!("{prefix}{}", missing.join(", "));
|
||||
(
|
||||
span,
|
||||
format!(
|
||||
"add the missing parameter{} from the trait",
|
||||
pluralize!(trait_number_args - impl_number_args)
|
||||
),
|
||||
replacement,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
Ordering::Less => impl_inputs_span.and_then(|full| {
|
||||
// Span of the arguments that there are too many of:
|
||||
// fn foo(a: i32, b: u32) {}
|
||||
// ^^^^^^^^
|
||||
let lo = if trait_number_args == 0 {
|
||||
full.lo()
|
||||
} else {
|
||||
impl_m_sig
|
||||
.decl
|
||||
.inputs
|
||||
.get(trait_number_args - 1)
|
||||
.map(|arg| arg.span.hi())?
|
||||
};
|
||||
let span = full.with_lo(lo);
|
||||
Some((
|
||||
span,
|
||||
format!(
|
||||
"remove the extra parameter{} to match the trait",
|
||||
pluralize!(impl_number_args - trait_number_args)
|
||||
),
|
||||
String::new(),
|
||||
))
|
||||
}),
|
||||
Ordering::Equal => unreachable!(),
|
||||
};
|
||||
if let Some((span, msg, replacement)) = suggestion {
|
||||
err.span_suggestion_verbose(span, msg, replacement, Applicability::MaybeIncorrect);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(err.emit_unless_delay(delay));
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
||||
| sym::fabsf128
|
||||
| sym::fadd_algebraic
|
||||
| sym::fdiv_algebraic
|
||||
| sym::field_offset
|
||||
| sym::floorf16
|
||||
| sym::floorf32
|
||||
| sym::floorf64
|
||||
@@ -297,6 +298,7 @@ pub(crate) fn check_intrinsic_type(
|
||||
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
|
||||
}
|
||||
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
|
||||
sym::field_offset => (1, 0, vec![], tcx.types.usize),
|
||||
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
|
||||
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
|
||||
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => {
|
||||
|
||||
@@ -88,6 +88,8 @@ pub(crate) enum AssocItemNotFoundLabel<'a> {
|
||||
NotFound {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
assoc_ident: Ident,
|
||||
assoc_kind: &'static str,
|
||||
},
|
||||
#[label(
|
||||
"there is {$identically_named ->
|
||||
@@ -149,6 +151,7 @@ pub(crate) enum AssocItemNotFoundSugg<'a> {
|
||||
trait_ref: String,
|
||||
suggested_name: Symbol,
|
||||
identically_named: bool,
|
||||
assoc_kind: &'static str,
|
||||
#[applicability]
|
||||
applicability: Applicability,
|
||||
},
|
||||
@@ -1446,6 +1449,15 @@ pub struct NoVariantNamed<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field `{$field}` on type `{$ty}`", code = E0609)]
|
||||
pub struct NoFieldOnType<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub field: Ident,
|
||||
}
|
||||
|
||||
// FIXME(fmease): Deduplicate:
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -141,7 +141,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
);
|
||||
}
|
||||
|
||||
let assoc_kind_str = assoc_tag_str(assoc_tag);
|
||||
let assoc_kind = assoc_tag_str(assoc_tag);
|
||||
let qself_str = qself.to_string(tcx);
|
||||
|
||||
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
|
||||
@@ -151,7 +151,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
let mut err = errors::AssocItemNotFound {
|
||||
span: if is_dummy { span } else { assoc_ident.span },
|
||||
assoc_ident,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_kind,
|
||||
qself: &qself_str,
|
||||
label: None,
|
||||
sugg: None,
|
||||
@@ -161,7 +161,8 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
};
|
||||
|
||||
if is_dummy {
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
|
||||
err.label =
|
||||
Some(errors::AssocItemNotFoundLabel::NotFound { span, assoc_ident, assoc_kind });
|
||||
return self.dcx().emit_err(err);
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
{
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Similar {
|
||||
span: assoc_ident.span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_kind,
|
||||
suggested_name,
|
||||
});
|
||||
return self.dcx().emit_err(err);
|
||||
@@ -224,7 +225,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
let trait_name = tcx.def_path_str(best_trait);
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::FoundInOtherTrait {
|
||||
span: assoc_ident.span,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_kind,
|
||||
trait_name: &trait_name,
|
||||
suggested_name,
|
||||
identically_named: suggested_name == assoc_ident.name,
|
||||
@@ -256,7 +257,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait {
|
||||
span: assoc_ident.span,
|
||||
trait_name: &trait_name,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_kind,
|
||||
suggested_name,
|
||||
});
|
||||
return self.dcx().emit_err(err);
|
||||
@@ -286,6 +287,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
trait_ref,
|
||||
identically_named,
|
||||
suggested_name,
|
||||
assoc_kind,
|
||||
applicability,
|
||||
});
|
||||
} else {
|
||||
@@ -322,11 +324,15 @@ pub(super) fn report_unresolved_assoc_item<I>(
|
||||
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
|
||||
span: assoc_ident.span,
|
||||
qself: &qself_str,
|
||||
assoc_kind: assoc_kind_str,
|
||||
assoc_kind,
|
||||
suggested_name: *candidate_name,
|
||||
});
|
||||
} else {
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_ident.span });
|
||||
err.label = Some(errors::AssocItemNotFoundLabel::NotFound {
|
||||
span: assoc_ident.span,
|
||||
assoc_ident,
|
||||
assoc_kind,
|
||||
});
|
||||
}
|
||||
|
||||
self.dcx().emit_err(err)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
use std::slice;
|
||||
|
||||
use rustc_abi::FIRST_VARIANT;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
@@ -50,11 +51,11 @@
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::check::check_abi;
|
||||
use crate::check_c_variadic_abi;
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoFieldOnType};
|
||||
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
use crate::{NoVariantNamed, check_c_variadic_abi};
|
||||
|
||||
/// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness
|
||||
/// trait or a default trait)
|
||||
@@ -3050,6 +3051,14 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.record_ty(pat.hir_id, ty, pat.span);
|
||||
pat_ty
|
||||
}
|
||||
hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => self.lower_field_of(
|
||||
self.lower_ty(ty),
|
||||
self.item_def_id(),
|
||||
ty.span,
|
||||
hir_ty.hir_id,
|
||||
*variant,
|
||||
*field,
|
||||
),
|
||||
hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
|
||||
};
|
||||
|
||||
@@ -3091,6 +3100,159 @@ fn lower_pat_ty_pat(
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_field_of(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
ty_span: Span,
|
||||
hir_id: HirId,
|
||||
variant: Option<Ident>,
|
||||
field: Ident,
|
||||
) -> Ty<'tcx> {
|
||||
let dcx = self.dcx();
|
||||
let tcx = self.tcx();
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
let base_did = def.did();
|
||||
let kind_name = tcx.def_descr(base_did);
|
||||
let (variant_idx, variant) = if def.is_enum() {
|
||||
let Some(variant) = variant else {
|
||||
let err = dcx
|
||||
.create_err(NoVariantNamed { span: field.span, ident: field, ty })
|
||||
.with_span_help(
|
||||
field.span.shrink_to_lo(),
|
||||
"you might be missing a variant here: `Variant.`",
|
||||
)
|
||||
.emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
};
|
||||
|
||||
if let Some(res) = def
|
||||
.variants()
|
||||
.iter_enumerated()
|
||||
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == variant)
|
||||
{
|
||||
res
|
||||
} else {
|
||||
let err = dcx
|
||||
.create_err(NoVariantNamed { span: variant.span, ident: variant, ty })
|
||||
.emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
}
|
||||
} else {
|
||||
if let Some(variant) = variant {
|
||||
let adt_path = tcx.def_path_str(base_did);
|
||||
struct_span_code_err!(
|
||||
dcx,
|
||||
variant.span,
|
||||
E0609,
|
||||
"{kind_name} `{adt_path}` does not have any variants",
|
||||
)
|
||||
.with_span_label(variant.span, "variant unknown")
|
||||
.emit();
|
||||
}
|
||||
(FIRST_VARIANT, def.non_enum_variant())
|
||||
};
|
||||
let block = tcx.local_def_id_to_hir_id(item_def_id);
|
||||
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(field, def.did(), block);
|
||||
if let Some((field_idx, field)) = variant
|
||||
.fields
|
||||
.iter_enumerated()
|
||||
.find(|(_, f)| f.ident(tcx).normalize_to_macros_2_0() == ident)
|
||||
{
|
||||
if field.vis.is_accessible_from(def_scope, tcx) {
|
||||
tcx.check_stability(field.did, Some(hir_id), ident.span, None);
|
||||
} else {
|
||||
let adt_path = tcx.def_path_str(base_did);
|
||||
struct_span_code_err!(
|
||||
dcx,
|
||||
ident.span,
|
||||
E0616,
|
||||
"field `{ident}` of {kind_name} `{adt_path}` is private",
|
||||
)
|
||||
.with_span_label(ident.span, "private field")
|
||||
.emit();
|
||||
}
|
||||
Ty::new_field_representing_type(tcx, ty, variant_idx, field_idx)
|
||||
} else {
|
||||
let err =
|
||||
dcx.create_err(NoFieldOnType { span: ident.span, field: ident, ty }).emit();
|
||||
Ty::new_error(tcx, err)
|
||||
}
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
let index = match field.as_str().parse::<usize>() {
|
||||
Ok(idx) => idx,
|
||||
Err(_) => {
|
||||
let err =
|
||||
dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
|
||||
return Ty::new_error(tcx, err);
|
||||
}
|
||||
};
|
||||
if field.name != sym::integer(index) {
|
||||
bug!("we parsed above, but now not equal?");
|
||||
}
|
||||
if tys.get(index).is_some() {
|
||||
Ty::new_field_representing_type(tcx, ty, FIRST_VARIANT, index.into())
|
||||
} else {
|
||||
let err = dcx.create_err(NoFieldOnType { span: field.span, field, ty }).emit();
|
||||
Ty::new_error(tcx, err)
|
||||
}
|
||||
}
|
||||
// FIXME(FRTs): support type aliases
|
||||
/*
|
||||
ty::Alias(AliasTyKind::Free, ty) => {
|
||||
return self.lower_field_of(
|
||||
ty,
|
||||
item_def_id,
|
||||
ty_span,
|
||||
hir_id,
|
||||
variant,
|
||||
field,
|
||||
);
|
||||
}*/
|
||||
ty::Alias(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("could not resolve fields of `{ty}`")),
|
||||
),
|
||||
ty::Error(err) => Ty::new_error(tcx, *err),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_, _)
|
||||
| ty::UnsafeBinder(_)
|
||||
| ty::Dynamic(_, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(_, _)
|
||||
| ty::Never
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Slice(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("type `{ty}` doesn't have fields")),
|
||||
),
|
||||
ty::Infer(_) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("cannot use `{ty}` in this position")),
|
||||
),
|
||||
// FIXME(FRTs): support these types?
|
||||
ty::Array(..) | ty::Pat(..) => Ty::new_error(
|
||||
tcx,
|
||||
dcx.span_err(ty_span, format!("type `{ty}` is not yet supported in `field_of!`")),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use rustc_hir::{
|
||||
BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound,
|
||||
GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind,
|
||||
PreciseCapturingArg, RangeEnd, Term, TyPatKind,
|
||||
PreciseCapturingArg, RangeEnd, Term, TyFieldPath, TyPatKind,
|
||||
};
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym};
|
||||
@@ -464,6 +464,17 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
|
||||
self.word(" is ");
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
hir::TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
|
||||
self.word("field_of!(");
|
||||
self.print_type(ty);
|
||||
self.word(", ");
|
||||
if let Some(variant) = *variant {
|
||||
self.print_ident(variant);
|
||||
self.word(".");
|
||||
}
|
||||
self.print_ident(*field);
|
||||
self.word(")");
|
||||
}
|
||||
}
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
@@ -490,15 +490,6 @@ pub(crate) fn new() -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field `{$field}` on type `{$ty}`", code = E0609)]
|
||||
pub(crate) struct NoFieldOnType<'tcx> {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ty: Ty<'tcx>,
|
||||
pub(crate) field: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("no field named `{$field}` on enum variant `{$container}::{$ident}`", code = E0609)]
|
||||
pub(crate) struct NoFieldOnVariant<'tcx> {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
|
||||
use rustc_hir_analysis::NoVariantNamed;
|
||||
use rustc_hir_analysis::errors::NoFieldOnType;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
@@ -43,7 +44,7 @@
|
||||
use crate::errors::{
|
||||
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
|
||||
BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer,
|
||||
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType,
|
||||
FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn,
|
||||
NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
|
||||
TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
|
||||
};
|
||||
|
||||
@@ -49,7 +49,9 @@
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::solve;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::FnCtxt;
|
||||
@@ -196,17 +198,17 @@ fn analyze_closure(
|
||||
let closure_def_id = closure_def_id.expect_local();
|
||||
|
||||
assert_eq!(self.tcx.hir_body_owner_def_id(body.id()), closure_def_id);
|
||||
|
||||
let closure_fcx = FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id);
|
||||
|
||||
let mut delegate = InferBorrowKind {
|
||||
fcx: &closure_fcx,
|
||||
closure_def_id,
|
||||
capture_information: Default::default(),
|
||||
fake_reads: Default::default(),
|
||||
};
|
||||
|
||||
let _ = euv::ExprUseVisitor::new(
|
||||
&FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id),
|
||||
&mut delegate,
|
||||
)
|
||||
.consume_body(body);
|
||||
let _ = euv::ExprUseVisitor::new(&closure_fcx, &mut delegate).consume_body(body);
|
||||
|
||||
// There are several curious situations with coroutine-closures where
|
||||
// analysis is too aggressive with borrows when the coroutine-closure is
|
||||
@@ -286,7 +288,7 @@ fn analyze_closure(
|
||||
let hir::def::Res::Local(local_id) = path.res else {
|
||||
bug!();
|
||||
};
|
||||
let place = self.place_for_root_variable(closure_def_id, local_id);
|
||||
let place = closure_fcx.place_for_root_variable(closure_def_id, local_id);
|
||||
delegate.capture_information.push((
|
||||
place,
|
||||
ty::CaptureInfo {
|
||||
@@ -325,7 +327,7 @@ fn analyze_closure(
|
||||
|
||||
if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
|
||||
for var_hir_id in upvars.keys() {
|
||||
let place = self.place_for_root_variable(closure_def_id, *var_hir_id);
|
||||
let place = closure_fcx.place_for_root_variable(closure_def_id, *var_hir_id);
|
||||
|
||||
debug!("seed place {:?}", place);
|
||||
|
||||
@@ -559,17 +561,17 @@ fn coroutine_body_consumes_upvars(
|
||||
bug!();
|
||||
};
|
||||
|
||||
let coroutine_fcx =
|
||||
FnCtxt::new(self, self.tcx.param_env(coroutine_def_id), coroutine_def_id);
|
||||
|
||||
let mut delegate = InferBorrowKind {
|
||||
fcx: &coroutine_fcx,
|
||||
closure_def_id: coroutine_def_id,
|
||||
capture_information: Default::default(),
|
||||
fake_reads: Default::default(),
|
||||
};
|
||||
|
||||
let _ = euv::ExprUseVisitor::new(
|
||||
&FnCtxt::new(self, self.tcx.param_env(coroutine_def_id), coroutine_def_id),
|
||||
&mut delegate,
|
||||
)
|
||||
.consume_expr(body);
|
||||
let _ = euv::ExprUseVisitor::new(&coroutine_fcx, &mut delegate).consume_expr(body);
|
||||
|
||||
let (_, kind, _) = self.process_collected_capture_information(
|
||||
hir::CaptureBy::Ref,
|
||||
@@ -1125,6 +1127,45 @@ fn perform_2229_migration_analysis(
|
||||
);
|
||||
}
|
||||
}
|
||||
fn normalize_capture_place(&self, span: Span, place: Place<'tcx>) -> Place<'tcx> {
|
||||
let mut place = self.resolve_vars_if_possible(place);
|
||||
|
||||
// In the new solver, types in HIR `Place`s can contain unnormalized aliases,
|
||||
// which can ICE later (e.g. when projecting fields for diagnostics).
|
||||
if self.next_trait_solver() {
|
||||
let cause = self.misc(span);
|
||||
let at = self.at(&cause, self.param_env);
|
||||
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
|
||||
at,
|
||||
place.clone(),
|
||||
vec![],
|
||||
) {
|
||||
Ok((normalized, goals)) => {
|
||||
if !goals.is_empty() {
|
||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||
typeck_results.coroutine_stalled_predicates.extend(
|
||||
goals
|
||||
.into_iter()
|
||||
// FIXME: throwing away the param-env :(
|
||||
.map(|goal| (goal.predicate, self.misc(span))),
|
||||
);
|
||||
}
|
||||
normalized
|
||||
}
|
||||
Err(errors) => {
|
||||
let guar = self.infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||
place.base_ty = Ty::new_error(self.tcx, guar);
|
||||
for proj in &mut place.projections {
|
||||
proj.ty = Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
place
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For the old solver we can rely on `normalize` to eagerly normalize aliases.
|
||||
self.normalize(span, place)
|
||||
}
|
||||
}
|
||||
|
||||
/// Combines all the reasons for 2229 migrations
|
||||
fn compute_2229_migrations_reasons(
|
||||
@@ -1734,11 +1775,15 @@ fn place_for_root_variable(
|
||||
) -> Place<'tcx> {
|
||||
let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id);
|
||||
|
||||
Place {
|
||||
let place = Place {
|
||||
base_ty: self.node_ty(var_hir_id),
|
||||
base: PlaceBase::Upvar(upvar_id),
|
||||
projections: Default::default(),
|
||||
}
|
||||
};
|
||||
|
||||
// Normalize eagerly when inserting into `capture_information`, so all downstream
|
||||
// capture analysis can assume a normalized `Place`.
|
||||
self.normalize_capture_place(self.tcx.hir_span(var_hir_id), place)
|
||||
}
|
||||
|
||||
fn should_log_capture_analysis(&self, closure_def_id: LocalDefId) -> bool {
|
||||
@@ -1994,7 +2039,8 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: HirId) -> Span {
|
||||
tcx.sess.source_map().end_point(owner_span)
|
||||
}
|
||||
|
||||
struct InferBorrowKind<'tcx> {
|
||||
struct InferBorrowKind<'fcx, 'a, 'tcx> {
|
||||
fcx: &'fcx FnCtxt<'a, 'tcx>,
|
||||
// The def-id of the closure whose kind and upvar accesses are being inferred.
|
||||
closure_def_id: LocalDefId,
|
||||
|
||||
@@ -2028,7 +2074,7 @@ struct InferBorrowKind<'tcx> {
|
||||
fake_reads: Vec<(Place<'tcx>, FakeReadCause, HirId)>,
|
||||
}
|
||||
|
||||
impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
|
||||
impl<'fcx, 'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'fcx, 'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn fake_read(
|
||||
&mut self,
|
||||
@@ -2042,8 +2088,10 @@ fn fake_read(
|
||||
// such as deref of a raw pointer.
|
||||
let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable);
|
||||
|
||||
let (place, _) =
|
||||
restrict_capture_precision(place_with_id.place.clone(), dummy_capture_kind);
|
||||
let span = self.fcx.tcx.hir_span(diag_expr_id);
|
||||
let place = self.fcx.normalize_capture_place(span, place_with_id.place.clone());
|
||||
|
||||
let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
|
||||
|
||||
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
|
||||
self.fake_reads.push((place, cause, diag_expr_id));
|
||||
@@ -2054,8 +2102,11 @@ fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId)
|
||||
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
|
||||
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
|
||||
|
||||
let span = self.fcx.tcx.hir_span(diag_expr_id);
|
||||
let place = self.fcx.normalize_capture_place(span, place_with_id.place.clone());
|
||||
|
||||
self.capture_information.push((
|
||||
place_with_id.place.clone(),
|
||||
place,
|
||||
ty::CaptureInfo {
|
||||
capture_kind_expr_id: Some(diag_expr_id),
|
||||
path_expr_id: Some(diag_expr_id),
|
||||
@@ -2069,8 +2120,11 @@ fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: Hir
|
||||
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
|
||||
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
|
||||
|
||||
let span = self.fcx.tcx.hir_span(diag_expr_id);
|
||||
let place = self.fcx.normalize_capture_place(span, place_with_id.place.clone());
|
||||
|
||||
self.capture_information.push((
|
||||
place_with_id.place.clone(),
|
||||
place,
|
||||
ty::CaptureInfo {
|
||||
capture_kind_expr_id: Some(diag_expr_id),
|
||||
path_expr_id: Some(diag_expr_id),
|
||||
@@ -2092,14 +2146,16 @@ fn borrow(
|
||||
// The region here will get discarded/ignored
|
||||
let capture_kind = ty::UpvarCapture::ByRef(bk);
|
||||
|
||||
let span = self.fcx.tcx.hir_span(diag_expr_id);
|
||||
let place = self.fcx.normalize_capture_place(span, place_with_id.place.clone());
|
||||
|
||||
// We only want repr packed restriction to be applied to reading references into a packed
|
||||
// struct, and not when the data is being moved. Therefore we call this method here instead
|
||||
// of in `restrict_capture_precision`.
|
||||
let (place, mut capture_kind) =
|
||||
restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind);
|
||||
let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(place, capture_kind);
|
||||
|
||||
// Raw pointers don't inherit mutability
|
||||
if place_with_id.place.deref_tys().any(Ty::is_raw_ptr) {
|
||||
if place.deref_tys().any(Ty::is_raw_ptr) {
|
||||
capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::Immutable);
|
||||
}
|
||||
|
||||
|
||||
@@ -2320,8 +2320,9 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
|
||||
if features.incomplete(name) {
|
||||
let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
|
||||
.map(|n| BuiltinFeatureIssueNote { n });
|
||||
let help =
|
||||
HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
|
||||
let help = HAS_MIN_FEATURES
|
||||
.contains(&name)
|
||||
.then_some(BuiltinIncompleteFeaturesHelp { name });
|
||||
|
||||
cx.emit_span_lint(
|
||||
INCOMPLETE_FEATURES,
|
||||
|
||||
@@ -87,7 +87,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
ty::AssocTag::Type,
|
||||
item.owner_id.to_def_id(),
|
||||
)
|
||||
.map(|label| SupertraitAsDerefTargetLabel { label: tcx.def_span(label.def_id) });
|
||||
.map(|label| SupertraitAsDerefTargetLabel {
|
||||
label: tcx.def_span(label.def_id),
|
||||
self_ty,
|
||||
});
|
||||
let span = tcx.def_span(item.owner_id.def_id);
|
||||
cx.emit_span_lint(
|
||||
DEREF_INTO_DYN_SUPERTRAIT,
|
||||
|
||||
@@ -105,13 +105,11 @@ pub fn decorate_builtin_lint(
|
||||
BuiltinLintDiag::RedundantImport(spans, ident) => {
|
||||
let subs = spans
|
||||
.into_iter()
|
||||
.map(|(span, is_imported)| {
|
||||
(match (span.is_dummy(), is_imported) {
|
||||
(false, true) => lints::RedundantImportSub::ImportedHere,
|
||||
(false, false) => lints::RedundantImportSub::DefinedHere,
|
||||
(true, true) => lints::RedundantImportSub::ImportedPrelude,
|
||||
(true, false) => lints::RedundantImportSub::DefinedPrelude,
|
||||
})(span)
|
||||
.map(|(span, is_imported)| match (span.is_dummy(), is_imported) {
|
||||
(false, true) => lints::RedundantImportSub::ImportedHere { span, ident },
|
||||
(false, false) => lints::RedundantImportSub::DefinedHere { span, ident },
|
||||
(true, true) => lints::RedundantImportSub::ImportedPrelude { span, ident },
|
||||
(true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident },
|
||||
})
|
||||
.collect();
|
||||
lints::RedundantImport { subs, ident }.decorate_lint(diag);
|
||||
|
||||
@@ -105,9 +105,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
Some(ConstItemInteriorMutationsSuggestionStatic::Spanful {
|
||||
const_: const_item.vis_span.between(ident.span),
|
||||
before: if !vis_span.is_empty() { " " } else { "" },
|
||||
const_name,
|
||||
})
|
||||
} else {
|
||||
Some(ConstItemInteriorMutationsSuggestionStatic::Spanless)
|
||||
Some(ConstItemInteriorMutationsSuggestionStatic::Spanless { const_name })
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -532,7 +532,9 @@ pub(crate) struct BuiltinInternalFeatures {
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help("consider using `min_{$name}` instead, which is more stable and complete")]
|
||||
pub(crate) struct BuiltinIncompleteFeaturesHelp;
|
||||
pub(crate) struct BuiltinIncompleteFeaturesHelp {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note("see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information")]
|
||||
@@ -663,14 +665,15 @@ pub(crate) struct SupertraitAsDerefTarget<'a> {
|
||||
)]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub label2: Option<SupertraitAsDerefTargetLabel>,
|
||||
pub label2: Option<SupertraitAsDerefTargetLabel<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label("target type is a supertrait of `{$self_ty}`")]
|
||||
pub(crate) struct SupertraitAsDerefTargetLabel {
|
||||
pub(crate) struct SupertraitAsDerefTargetLabel<'a> {
|
||||
#[primary_span]
|
||||
pub label: Span,
|
||||
pub self_ty: Ty<'a>,
|
||||
}
|
||||
|
||||
// enum_intrinsics_non_enums.rs
|
||||
@@ -958,9 +961,10 @@ pub(crate) enum ConstItemInteriorMutationsSuggestionStatic {
|
||||
#[primary_span]
|
||||
const_: Span,
|
||||
before: &'static str,
|
||||
const_name: Ident,
|
||||
},
|
||||
#[help("for a shared instance of `{$const_name}`, consider making it a `static` item instead")]
|
||||
Spanless,
|
||||
Spanless { const_name: Ident },
|
||||
}
|
||||
|
||||
// reference_casting.rs
|
||||
@@ -1972,11 +1976,8 @@ pub(crate) enum UseInclusiveRange<'a> {
|
||||
#[diag("literal out of range for `{$ty}`")]
|
||||
pub(crate) struct OverflowingBinHex<'a> {
|
||||
pub ty: &'a str,
|
||||
pub lit: String,
|
||||
pub dec: u128,
|
||||
pub actually: String,
|
||||
#[subdiagnostic]
|
||||
pub sign: OverflowingBinHexSign,
|
||||
pub sign: OverflowingBinHexSign<'a>,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<OverflowingBinHexSub<'a>>,
|
||||
#[subdiagnostic]
|
||||
@@ -1984,14 +1985,14 @@ pub(crate) struct OverflowingBinHex<'a> {
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum OverflowingBinHexSign {
|
||||
pub(crate) enum OverflowingBinHexSign<'a> {
|
||||
#[note(
|
||||
"the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}`"
|
||||
)]
|
||||
Positive,
|
||||
Positive { lit: String, ty: &'a str, actually: String, dec: u128 },
|
||||
#[note("the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`")]
|
||||
#[note("and the value `-{$lit}` will become `{$actually}{$ty}`")]
|
||||
Negative,
|
||||
Negative { lit: String, ty: &'a str, actually: String, dec: u128 },
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
@@ -2562,6 +2563,7 @@ pub(crate) struct UnusedDelimSuggestion {
|
||||
#[suggestion_part(code = "{end_replace}")]
|
||||
pub end_span: Span,
|
||||
pub end_replace: &'static str,
|
||||
pub delim: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@@ -3131,20 +3133,35 @@ pub(crate) enum UnusedImportsSugg {
|
||||
pub(crate) struct RedundantImport {
|
||||
#[subdiagnostic]
|
||||
pub subs: Vec<RedundantImportSub>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum RedundantImportSub {
|
||||
#[label("the item `{$ident}` is already imported here")]
|
||||
ImportedHere(#[primary_span] Span),
|
||||
ImportedHere {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
},
|
||||
#[label("the item `{$ident}` is already defined here")]
|
||||
DefinedHere(#[primary_span] Span),
|
||||
DefinedHere {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
},
|
||||
#[label("the item `{$ident}` is already imported by the extern prelude")]
|
||||
ImportedPrelude(#[primary_span] Span),
|
||||
ImportedPrelude {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
},
|
||||
#[label("the item `{$ident}` is already defined by the extern prelude")]
|
||||
DefinedPrelude(#[primary_span] Span),
|
||||
DefinedPrelude {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
|
||||
@@ -157,8 +157,21 @@ fn report_bin_hex_error(
|
||||
(t.name_str(), actually.to_string())
|
||||
}
|
||||
};
|
||||
let sign =
|
||||
if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive };
|
||||
let sign = if negative {
|
||||
OverflowingBinHexSign::Negative {
|
||||
lit: repr_str.clone(),
|
||||
dec: val,
|
||||
actually: actually.clone(),
|
||||
ty: t,
|
||||
}
|
||||
} else {
|
||||
OverflowingBinHexSign::Positive {
|
||||
lit: repr_str.clone(),
|
||||
dec: val,
|
||||
actually: actually.clone(),
|
||||
ty: t,
|
||||
}
|
||||
};
|
||||
let sub = get_type_suggestion(cx.typeck_results().node_type(hir_id), val, negative).map(
|
||||
|suggestion_ty| {
|
||||
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
|
||||
@@ -194,7 +207,7 @@ fn report_bin_hex_error(
|
||||
Some(OverflowingBinHexSignBitSub {
|
||||
span,
|
||||
lit_no_suffix,
|
||||
negative_val: actually.clone(),
|
||||
negative_val: actually,
|
||||
int_ty: int_ty.name_str(),
|
||||
uint_ty: Integer::fit_unsigned(val).uint_ty_str(),
|
||||
})
|
||||
@@ -204,15 +217,7 @@ fn report_bin_hex_error(
|
||||
cx.emit_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
span,
|
||||
OverflowingBinHex {
|
||||
ty: t,
|
||||
lit: repr_str.clone(),
|
||||
dec: val,
|
||||
actually,
|
||||
sign,
|
||||
sub,
|
||||
sign_bit_sub,
|
||||
},
|
||||
OverflowingBinHex { ty: t, sign, sub, sign_bit_sub },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -350,6 +350,7 @@ fn emit_unused_delims(
|
||||
start_replace: lo_replace,
|
||||
end_span: hi,
|
||||
end_replace: hi_replace,
|
||||
delim: Self::DELIM_STR,
|
||||
}
|
||||
});
|
||||
cx.emit_span_lint(
|
||||
|
||||
@@ -535,7 +535,7 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
|
||||
let mut calls = TokenStream::new();
|
||||
for (kind, messages) in kind_messages {
|
||||
let message = format_ident!("__message");
|
||||
let message_stream = messages.diag_message(None);
|
||||
let message_stream = messages.diag_message(Some(self.variant));
|
||||
calls.extend(quote! { let #message = #diag.eagerly_translate(#message_stream); });
|
||||
|
||||
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||
|
||||
@@ -315,7 +315,7 @@ fn add_library(
|
||||
crate_name: tcx.crate_name(cnum),
|
||||
non_static_deps: unavailable_as_static
|
||||
.drain(..)
|
||||
.map(|cnum| NonStaticCrateDep { crate_name_: tcx.crate_name(cnum) })
|
||||
.map(|cnum| NonStaticCrateDep { sub_crate_name: tcx.crate_name(cnum) })
|
||||
.collect(),
|
||||
rustc_driver_help: linking_to_rustc_driver,
|
||||
});
|
||||
|
||||
@@ -48,10 +48,10 @@ pub struct CrateDepMultiple {
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note("`{$crate_name}` was unavailable as a static crate, preventing fully static linking")]
|
||||
#[note("`{$sub_crate_name}` was unavailable as a static crate, preventing fully static linking")]
|
||||
pub struct NonStaticCrateDep {
|
||||
/// It's different from `crate_name` in main Diagnostic.
|
||||
pub crate_name_: Symbol,
|
||||
pub sub_crate_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::ops::Range;
|
||||
use std::str;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx};
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, ReprOptions, VariantIdx};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
@@ -15,6 +15,8 @@
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_session::DataTypeKind;
|
||||
use rustc_span::sym;
|
||||
use rustc_type_ir::FieldInfo;
|
||||
use rustc_type_ir::solve::AdtDestructorKind;
|
||||
use tracing::{debug, info, trace};
|
||||
|
||||
@@ -23,8 +25,8 @@
|
||||
};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty;
|
||||
use crate::ty::util::{Discr, IntTypeExt};
|
||||
use crate::ty::{self, ConstKind};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct AdtFlags(u16);
|
||||
@@ -58,6 +60,8 @@ impl AdtFlags: u16 {
|
||||
const IS_PIN = 1 << 11;
|
||||
/// Indicates whether the type is `#[pin_project]`.
|
||||
const IS_PIN_PROJECT = 1 << 12;
|
||||
/// Indicates whether the type is `FieldRepresentingType`.
|
||||
const IS_FIELD_REPRESENTING_TYPE = 1 << 13;
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
||||
@@ -200,6 +204,51 @@ pub fn flags(self) -> AdtFlags {
|
||||
pub fn repr(self) -> ReprOptions {
|
||||
self.0.0.repr
|
||||
}
|
||||
|
||||
pub fn field_representing_type_info(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Option<FieldInfo<TyCtxt<'tcx>>> {
|
||||
if !self.is_field_representing_type() {
|
||||
return None;
|
||||
}
|
||||
let base = args.type_at(0);
|
||||
let variant_idx = match args.const_at(1).kind() {
|
||||
ConstKind::Value(v) => VariantIdx::from_u32(v.to_leaf().to_u32()),
|
||||
_ => return None,
|
||||
};
|
||||
let field_idx = match args.const_at(2).kind() {
|
||||
ConstKind::Value(v) => FieldIdx::from_u32(v.to_leaf().to_u32()),
|
||||
_ => return None,
|
||||
};
|
||||
let (ty, variant, name) = match base.kind() {
|
||||
ty::Adt(base_def, base_args) => {
|
||||
let variant = base_def.variant(variant_idx);
|
||||
let field = &variant.fields[field_idx];
|
||||
(field.ty(tcx, base_args), base_def.is_enum().then_some(variant.name), field.name)
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
if variant_idx != FIRST_VARIANT {
|
||||
bug!("expected variant of tuple to be FIRST_VARIANT, but found {variant_idx:?}")
|
||||
}
|
||||
(
|
||||
if let Some(ty) = tys.get(field_idx.index()) {
|
||||
*ty
|
||||
} else {
|
||||
bug!(
|
||||
"expected valid tuple index, but got {field_idx:?}, tuple length: {}",
|
||||
tys.len()
|
||||
)
|
||||
},
|
||||
None,
|
||||
sym::integer(field_idx.index()),
|
||||
)
|
||||
}
|
||||
_ => panic!(),
|
||||
};
|
||||
Some(FieldInfo { base, ty, variant, variant_idx, name, field_idx })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
@@ -211,6 +260,10 @@ fn is_struct(self) -> bool {
|
||||
self.is_struct()
|
||||
}
|
||||
|
||||
fn is_packed(self) -> bool {
|
||||
self.repr().packed()
|
||||
}
|
||||
|
||||
fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
Some(interner.type_of(self.non_enum_variant().tail_opt()?.did))
|
||||
}
|
||||
@@ -223,6 +276,14 @@ fn is_manually_drop(self) -> bool {
|
||||
self.is_manually_drop()
|
||||
}
|
||||
|
||||
fn field_representing_type_info(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Option<FieldInfo<TyCtxt<'tcx>>> {
|
||||
self.field_representing_type_info(tcx, args)
|
||||
}
|
||||
|
||||
fn all_field_tys(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@@ -321,6 +382,9 @@ pub(super) fn new(
|
||||
if tcx.is_lang_item(did, LangItem::Pin) {
|
||||
flags |= AdtFlags::IS_PIN;
|
||||
}
|
||||
if tcx.is_lang_item(did, LangItem::FieldRepresentingType) {
|
||||
flags |= AdtFlags::IS_FIELD_REPRESENTING_TYPE;
|
||||
}
|
||||
|
||||
AdtDefData { did, variants, flags, repr }
|
||||
}
|
||||
@@ -449,6 +513,10 @@ pub fn is_pin_project(self) -> bool {
|
||||
self.flags().contains(AdtFlags::IS_PIN_PROJECT)
|
||||
}
|
||||
|
||||
pub fn is_field_representing_type(self) -> bool {
|
||||
self.flags().contains(AdtFlags::IS_FIELD_REPRESENTING_TYPE)
|
||||
}
|
||||
|
||||
/// Returns `true` if this type has a destructor.
|
||||
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.destructor(tcx).is_some()
|
||||
|
||||
@@ -755,6 +755,8 @@ fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FieldBase,
|
||||
FieldType,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
@@ -786,6 +788,7 @@ fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Field,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use rustc_macros::{Lift, extension};
|
||||
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
|
||||
use rustc_span::{Ident, RemapPathScopeComponents, Symbol, kw, sym};
|
||||
use rustc_type_ir::{Upcast as _, elaborate};
|
||||
use rustc_type_ir::{FieldInfo, Upcast as _, elaborate};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
// `pretty` is a separate module only for organization.
|
||||
@@ -793,6 +793,16 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
|
||||
false => write!(self, "{}", self.tcx().item_name(def_id))?,
|
||||
},
|
||||
},
|
||||
ty::Adt(def, args)
|
||||
if let Some(FieldInfo { base, variant, name, .. }) =
|
||||
def.field_representing_type_info(self.tcx(), args) =>
|
||||
{
|
||||
if let Some(variant) = variant {
|
||||
write!(self, "field_of!({base}, {variant}.{name})")?;
|
||||
} else {
|
||||
write!(self, "field_of!({base}, {name})")?;
|
||||
}
|
||||
}
|
||||
ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
|
||||
ty::Dynamic(data, r) => {
|
||||
let print_r = self.should_print_optional_region(r);
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region, Ty,
|
||||
TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
self, AdtDef, Const, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region,
|
||||
Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, ValTree,
|
||||
};
|
||||
|
||||
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
||||
@@ -487,6 +487,35 @@ pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<
|
||||
Ty::new(tcx, Pat(base, pat))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_field_representing_type(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
base: Ty<'tcx>,
|
||||
variant: VariantIdx,
|
||||
field: FieldIdx,
|
||||
) -> Ty<'tcx> {
|
||||
let Some(did) = tcx.lang_items().field_representing_type() else {
|
||||
bug!("could not locate the `FieldRepresentingType` lang item")
|
||||
};
|
||||
let def = tcx.adt_def(did);
|
||||
let args = tcx.mk_args(&[
|
||||
base.into(),
|
||||
Const::new_value(
|
||||
tcx,
|
||||
ValTree::from_scalar_int(tcx, variant.as_u32().into()),
|
||||
tcx.types.u32,
|
||||
)
|
||||
.into(),
|
||||
Const::new_value(
|
||||
tcx,
|
||||
ValTree::from_scalar_int(tcx, field.as_u32().into()),
|
||||
tcx.types.u32,
|
||||
)
|
||||
.into(),
|
||||
]);
|
||||
Ty::new_adt(tcx, def, args)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
|
||||
|
||||
@@ -115,12 +115,12 @@ fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool
|
||||
CallToDeprecatedSafeFnRequiresUnsafe {
|
||||
span,
|
||||
function: with_no_trimmed_paths!(self.tcx.def_path_str(id)),
|
||||
guarantee,
|
||||
sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
|
||||
start_of_line_suggestion: suggestion,
|
||||
start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
|
||||
left: span.shrink_to_lo(),
|
||||
right: span.shrink_to_hi(),
|
||||
guarantee,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -15,7 +15,6 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe {
|
||||
#[label("call to unsafe function")]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) function: String,
|
||||
pub(crate) guarantee: String,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sub: CallToDeprecatedSafeFnRequiresUnsafeSub,
|
||||
}
|
||||
@@ -33,6 +32,7 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub {
|
||||
pub(crate) left: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
pub(crate) right: Span,
|
||||
pub(crate) guarantee: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -389,4 +389,5 @@ pub(crate) struct ForceInlineFailure {
|
||||
#[note("`{$callee}` is required to be inlined to: {$sym}")]
|
||||
pub(crate) struct ForceInlineJustification {
|
||||
pub sym: Symbol,
|
||||
pub callee: String,
|
||||
}
|
||||
|
||||
@@ -251,15 +251,17 @@ fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str) {
|
||||
};
|
||||
|
||||
let call_span = callsite.source_info.span;
|
||||
let callee = tcx.def_path_str(callsite.callee.def_id());
|
||||
tcx.dcx().emit_err(crate::errors::ForceInlineFailure {
|
||||
call_span,
|
||||
attr_span,
|
||||
caller_span: tcx.def_span(self.def_id),
|
||||
caller: tcx.def_path_str(self.def_id),
|
||||
callee_span: tcx.def_span(callsite.callee.def_id()),
|
||||
callee: tcx.def_path_str(callsite.callee.def_id()),
|
||||
callee: callee.clone(),
|
||||
reason,
|
||||
justification: justification.map(|sym| crate::errors::ForceInlineJustification { sym }),
|
||||
justification: justification
|
||||
.map(|sym| crate::errors::ForceInlineJustification { sym, callee }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@ impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
|
||||
/// use a binding level above `universe_indices.len()`, we fail.
|
||||
/// Returns a type with all bound vars replaced by placeholders,
|
||||
/// together with mappings from the new placeholders back to the original variable.
|
||||
///
|
||||
/// Panics if there are any bound vars that use a binding level above `universe_indices.len()`.
|
||||
pub fn replace_bound_vars<T: TypeFoldable<I>>(
|
||||
infcx: &'a Infcx,
|
||||
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
|
||||
|
||||
@@ -348,6 +348,11 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Vec<Candidate<I>>;
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
}
|
||||
|
||||
/// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit
|
||||
@@ -617,6 +622,7 @@ fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
|
||||
Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => {
|
||||
G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
|
||||
}
|
||||
Some(SolverTraitLangItem::Field) => G::consider_builtin_field_candidate(self, goal),
|
||||
_ => Err(NoSolution),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -430,6 +430,13 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
) -> Vec<Candidate<I>> {
|
||||
unreachable!("Unsize is not const")
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, D>,
|
||||
_goal: Goal<<D as SolverDelegate>::Interner, Self>,
|
||||
) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolution> {
|
||||
unreachable!("Field is not const")
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
///
|
||||
/// We previously used `cx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this.
|
||||
/// However, it feels unlikely that uncreasing the recursion limit by a power of two
|
||||
/// to get one more iteration is every useful or desirable. We now instead used a constant
|
||||
/// to get one more iteration is ever useful or desirable. We now instead used a constant
|
||||
/// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations
|
||||
/// is required, we can add a new attribute for that or revert this to be dependant on the
|
||||
/// is required, we can add a new attribute for that or revert this to be dependent on the
|
||||
/// recursion limit again. However, this feels very unlikely.
|
||||
const FIXPOINT_STEP_LIMIT: usize = 8;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
|
||||
use rustc_type_ir::{self as ty, FieldInfo, Interner, NormalizesTo, PredicateKind, Upcast as _};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
@@ -950,6 +950,29 @@ fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
unreachable!("`BikeshedGuaranteedNoDrop` does not have an associated type: {:?}", goal)
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Adt(def, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
let Some(FieldInfo { base, ty, .. }) = def.field_representing_type_info(ecx.cx(), args)
|
||||
else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
let ty = match ecx.cx().as_lang_item(goal.predicate.def_id()) {
|
||||
Some(SolverLangItem::FieldBase) => base,
|
||||
Some(SolverLangItem::FieldType) => ty,
|
||||
_ => panic!("unexpected associated type {:?} in `Field`", goal.predicate),
|
||||
};
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.instantiate_normalizes_to_term(goal, ty.into());
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, SizedTraitKind,
|
||||
};
|
||||
use rustc_type_ir::{
|
||||
self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
|
||||
self as ty, FieldInfo, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
|
||||
TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
|
||||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
@@ -844,6 +844,54 @@ fn consider_structural_builtin_unsize_candidates(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_field_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
if let ty::Adt(def, args) = goal.predicate.self_ty().kind()
|
||||
&& let Some(FieldInfo { base, ty, .. }) =
|
||||
def.field_representing_type_info(ecx.cx(), args)
|
||||
&& {
|
||||
let sized_trait = ecx.cx().require_trait_lang_item(SolverTraitLangItem::Sized);
|
||||
// FIXME: add better support for builtin impls of traits that check for the bounds
|
||||
// on the trait definition in std.
|
||||
|
||||
// NOTE: these bounds have to be kept in sync with the definition of the `Field`
|
||||
// trait in `library/core/src/field.rs` as well as the old trait solver `fn
|
||||
// assemble_candidates_for_field_trait` in
|
||||
// `compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs`.
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: TraitRef::new(ecx.cx(), sized_trait, [base]).upcast(ecx.cx()),
|
||||
},
|
||||
);
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: TraitRef::new(ecx.cx(), sized_trait, [ty]).upcast(ecx.cx()),
|
||||
},
|
||||
);
|
||||
ecx.try_evaluate_added_goals()? == Certainty::Yes
|
||||
}
|
||||
&& match base.kind() {
|
||||
ty::Adt(def, _) => def.is_struct() && !def.is_packed(),
|
||||
ty::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Small helper function to change the `def_id` of a trait predicate - this is not normally
|
||||
|
||||
@@ -1016,7 +1016,6 @@ pub(crate) struct LeadingPlusNotSupported {
|
||||
pub(crate) struct ParenthesesWithStructFields {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub r#type: Path,
|
||||
#[subdiagnostic]
|
||||
pub braces_for_struct: BracesForStructLiteral,
|
||||
#[subdiagnostic]
|
||||
@@ -1029,6 +1028,7 @@ pub(crate) struct ParenthesesWithStructFields {
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct BracesForStructLiteral {
|
||||
pub r#type: Path,
|
||||
#[suggestion_part(code = " {{ ")]
|
||||
pub first: Span,
|
||||
#[suggestion_part(code = " }}")]
|
||||
@@ -1041,6 +1041,7 @@ pub(crate) struct BracesForStructLiteral {
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct NoFieldsForFnCall {
|
||||
pub r#type: Path,
|
||||
#[suggestion_part(code = "")]
|
||||
pub fields: Vec<Span>,
|
||||
}
|
||||
@@ -3176,6 +3177,7 @@ pub(crate) struct UnexpectedVertVertInPattern {
|
||||
pub(crate) struct TrailingVertSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub token: Token,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -118,16 +118,9 @@ pub fn new_parser_from_file<'a>(
|
||||
let msg = format!("couldn't read `{}`: {}", path.display(), e);
|
||||
let mut err = psess.dcx().struct_fatal(msg);
|
||||
if let Ok(contents) = std::fs::read(path)
|
||||
&& let Err(utf8err) = String::from_utf8(contents.clone())
|
||||
&& let Err(utf8err) = std::str::from_utf8(&contents)
|
||||
{
|
||||
utf8_error(
|
||||
sm,
|
||||
&path.display().to_string(),
|
||||
sp,
|
||||
&mut err,
|
||||
utf8err.utf8_error(),
|
||||
&contents,
|
||||
);
|
||||
utf8_error(sm, &path.display().to_string(), sp, &mut err, utf8err, &contents);
|
||||
}
|
||||
if let Some(sp) = sp {
|
||||
err.span(sp);
|
||||
|
||||
@@ -1140,7 +1140,7 @@ enum FloatComponent {
|
||||
/// Parse the field access used in offset_of, matched by `$(e:expr)+`.
|
||||
/// Currently returns a list of idents. However, it should be possible in
|
||||
/// future to also do array indices, which might be arbitrary expressions.
|
||||
fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
|
||||
pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
|
||||
let mut fields = Vec::new();
|
||||
let mut trailing_dot = None;
|
||||
|
||||
@@ -1309,12 +1309,13 @@ fn maybe_recover_struct_lit_bad_delims(
|
||||
self.dcx()
|
||||
.create_err(errors::ParenthesesWithStructFields {
|
||||
span,
|
||||
r#type: path,
|
||||
braces_for_struct: errors::BracesForStructLiteral {
|
||||
first: open_paren,
|
||||
second: close_paren,
|
||||
r#type: path.clone(),
|
||||
},
|
||||
no_fields_for_fn: errors::NoFieldsForFnCall {
|
||||
r#type: path,
|
||||
fields: fields
|
||||
.into_iter()
|
||||
.map(|field| field.span.until(field.expr.span))
|
||||
|
||||
@@ -364,6 +364,7 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
|
||||
start: lo,
|
||||
suggestion: TrailingVertSuggestion {
|
||||
span: self.prev_token.span.shrink_to_hi().with_hi(self.token.span.hi()),
|
||||
token: self.token,
|
||||
},
|
||||
token: self.token,
|
||||
note_double_vert: self.token.kind == token::OrOr,
|
||||
|
||||
@@ -329,6 +329,8 @@ fn parse_ty_common(
|
||||
self.parse_borrowed_pointee()?
|
||||
} else if self.eat_keyword_noexpect(kw::Typeof) {
|
||||
self.parse_typeof_ty(lo)?
|
||||
} else if self.is_builtin() {
|
||||
self.parse_builtin_ty()?
|
||||
} else if self.eat_keyword(exp!(Underscore)) {
|
||||
// A type to be inferred `_`
|
||||
TyKind::Infer
|
||||
@@ -802,6 +804,52 @@ fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> {
|
||||
Ok(TyKind::Err(guar))
|
||||
}
|
||||
|
||||
fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> {
|
||||
self.parse_builtin(|this, lo, ident| {
|
||||
Ok(match ident.name {
|
||||
sym::field_of => Some(this.parse_ty_field_of(lo)?),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> {
|
||||
let container = self.parse_ty()?;
|
||||
self.expect(exp!(Comma))?;
|
||||
|
||||
let fields = self.parse_floating_field_access()?;
|
||||
let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
|
||||
|
||||
if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {
|
||||
if trailing_comma {
|
||||
e.note("unexpected third argument to field_of");
|
||||
} else {
|
||||
e.note("field_of expects dot-separated field and variant names");
|
||||
}
|
||||
e.emit();
|
||||
}
|
||||
|
||||
// Eat tokens until the macro call ends.
|
||||
if self.may_recover() {
|
||||
while !self.token.kind.is_close_delim_or_eof() {
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
|
||||
match *fields {
|
||||
[] => Err(self.dcx().struct_span_err(
|
||||
self.token.span,
|
||||
"`field_of!` expects dot-separated field and variant names",
|
||||
)),
|
||||
[field] => Ok(TyKind::FieldOf(container, None, field)),
|
||||
[variant, field] => Ok(TyKind::FieldOf(container, Some(variant), field)),
|
||||
_ => Err(self.dcx().struct_span_err(
|
||||
fields.iter().map(|f| f.span).collect::<Vec<_>>(),
|
||||
"`field_of!` only supports a single field or a variant with a field",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a function pointer type (`TyKind::FnPtr`).
|
||||
/// ```ignore (illustrative)
|
||||
/// [unsafe] [extern "ABI"] fn (S) -> T
|
||||
|
||||
@@ -410,6 +410,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
|
||||
TraitObject,
|
||||
Infer,
|
||||
Pat,
|
||||
FieldOf,
|
||||
Err
|
||||
]
|
||||
);
|
||||
@@ -688,6 +689,7 @@ fn visit_ty(&mut self, t: &'v ast::Ty) {
|
||||
MacCall,
|
||||
CVarArgs,
|
||||
Dummy,
|
||||
FieldOf,
|
||||
Err
|
||||
]
|
||||
);
|
||||
|
||||
@@ -35,9 +35,9 @@ pub(crate) struct CycleStack {
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum StackCount {
|
||||
#[note("...which immediately requires {$stack_bottom} again")]
|
||||
Single,
|
||||
Single { stack_bottom: String },
|
||||
#[note("...which again requires {$stack_bottom}, completing the cycle")]
|
||||
Multiple,
|
||||
Multiple { stack_bottom: String },
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
||||
@@ -438,7 +438,12 @@ pub(crate) fn report_cycle<'a>(
|
||||
let mut cycle_stack = Vec::new();
|
||||
|
||||
use crate::error::StackCount;
|
||||
let stack_count = if stack.len() == 1 { StackCount::Single } else { StackCount::Multiple };
|
||||
let stack_bottom = stack[0].frame.info.description.to_owned();
|
||||
let stack_count = if stack.len() == 1 {
|
||||
StackCount::Single { stack_bottom: stack_bottom.clone() }
|
||||
} else {
|
||||
StackCount::Multiple { stack_bottom: stack_bottom.clone() }
|
||||
};
|
||||
|
||||
for i in 1..stack.len() {
|
||||
let frame = &stack[i].frame;
|
||||
@@ -467,7 +472,7 @@ pub(crate) fn report_cycle<'a>(
|
||||
let cycle_diag = crate::error::Cycle {
|
||||
span,
|
||||
cycle_stack,
|
||||
stack_bottom: stack[0].frame.info.description.to_owned(),
|
||||
stack_bottom,
|
||||
alias,
|
||||
cycle_usage,
|
||||
stack_count,
|
||||
|
||||
@@ -249,20 +249,23 @@ pub(crate) fn report_conflict(
|
||||
};
|
||||
|
||||
let label = match new_binding.is_import_user_facing() {
|
||||
true => errors::NameDefinedMultipleTimeLabel::Reimported { span },
|
||||
false => errors::NameDefinedMultipleTimeLabel::Redefined { span },
|
||||
true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name },
|
||||
false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name },
|
||||
};
|
||||
|
||||
let old_binding_label =
|
||||
(!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
|
||||
let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
|
||||
match old_binding.is_import_user_facing() {
|
||||
true => {
|
||||
errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind }
|
||||
}
|
||||
true => errors::NameDefinedMultipleTimeOldBindingLabel::Import {
|
||||
span,
|
||||
old_kind,
|
||||
name,
|
||||
},
|
||||
false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
|
||||
span,
|
||||
old_kind,
|
||||
name,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1126,11 +1126,13 @@ pub(crate) enum NameDefinedMultipleTimeLabel {
|
||||
Reimported {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
},
|
||||
#[label("`{$name}` redefined here")]
|
||||
Redefined {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1141,12 +1143,14 @@ pub(crate) enum NameDefinedMultipleTimeOldBindingLabel {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
old_kind: &'static str,
|
||||
name: Symbol,
|
||||
},
|
||||
#[label("previous definition of the {$old_kind} `{$name}` here")]
|
||||
Definition {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
old_kind: &'static str,
|
||||
name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1048,7 +1048,9 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
|
||||
message,
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
if !self.issue_145575_hack_applied {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
}
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
@@ -1072,7 +1074,9 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
|
||||
..
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
if !self.issue_145575_hack_applied {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
}
|
||||
let module = if let Some(ModuleOrUniformRoot::Module(m)) = module {
|
||||
m.opt_def_id()
|
||||
} else {
|
||||
|
||||
@@ -945,7 +945,15 @@
|
||||
ffi_const,
|
||||
ffi_pure,
|
||||
ffi_returns_twice,
|
||||
field,
|
||||
field_base,
|
||||
field_init_shorthand,
|
||||
field_of,
|
||||
field_offset,
|
||||
field_projections,
|
||||
field_representing_type,
|
||||
field_representing_type_raw,
|
||||
field_type,
|
||||
fields,
|
||||
file,
|
||||
final_associated_functions,
|
||||
|
||||
@@ -3288,12 +3288,14 @@ fn report_closure_error(
|
||||
err.fn_once_label = Some(ClosureFnOnceLabel {
|
||||
span: *span,
|
||||
place: ty::place_to_string_for_capture(self.tcx, place),
|
||||
trait_prefix,
|
||||
})
|
||||
}
|
||||
(ty::ClosureKind::FnMut, Some((span, place))) => {
|
||||
err.fn_mut_label = Some(ClosureFnMutLabel {
|
||||
span: *span,
|
||||
place: ty::place_to_string_for_capture(self.tcx, place),
|
||||
trait_prefix,
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -157,6 +157,7 @@ pub struct ClosureFnOnceLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub place: String,
|
||||
pub trait_prefix: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
@@ -165,6 +166,7 @@ pub struct ClosureFnMutLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub place: String,
|
||||
pub trait_prefix: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{
|
||||
self, Term, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast,
|
||||
self, FieldInfo, Term, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::sym;
|
||||
@@ -987,6 +987,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
| LangItem::Future
|
||||
| LangItem::Iterator
|
||||
| LangItem::AsyncIterator
|
||||
| LangItem::Field
|
||||
| LangItem::Fn
|
||||
| LangItem::FnMut
|
||||
| LangItem::FnOnce
|
||||
@@ -1547,6 +1548,20 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
|
||||
}
|
||||
});
|
||||
(metadata_ty.into(), obligations)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Field) {
|
||||
let ty::Adt(def, args) = self_ty.kind() else {
|
||||
bug!("only field representing types can implement `Field`")
|
||||
};
|
||||
let Some(FieldInfo { base, ty, .. }) = def.field_representing_type_info(tcx, args) else {
|
||||
bug!("only field representing types can implement `Field`")
|
||||
};
|
||||
if tcx.is_lang_item(item_def_id, LangItem::FieldBase) {
|
||||
(base.into(), PredicateObligations::new())
|
||||
} else if tcx.is_lang_item(item_def_id, LangItem::FieldType) {
|
||||
(ty.into(), PredicateObligations::new())
|
||||
} else {
|
||||
bug!("unexpected associated type {:?} in `Field`", obligation.predicate);
|
||||
}
|
||||
} else {
|
||||
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
|
||||
};
|
||||
|
||||
@@ -12,14 +12,18 @@
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, SizedTraitKind, Ty, TypeVisitableExt, TypingMode, elaborate};
|
||||
use rustc_middle::ty::{
|
||||
self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, TypingMode, elaborate,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::SelectionCandidate::*;
|
||||
use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::util;
|
||||
|
||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
@@ -128,6 +132,9 @@ pub(super) fn assemble_candidates<'o>(
|
||||
&mut candidates,
|
||||
);
|
||||
}
|
||||
Some(LangItem::Field) => {
|
||||
self.assemble_candidates_for_field_trait(obligation, &mut candidates);
|
||||
}
|
||||
_ => {
|
||||
// We re-match here for traits that can have both builtin impls and user written impls.
|
||||
// After the builtin impls we need to also add user written impls, which we do not want to
|
||||
@@ -1439,4 +1446,52 @@ fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_for_field_trait(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = obligation.predicate.self_ty().skip_binder().kind()
|
||||
&& let Some(FieldInfo { base, ty, .. }) =
|
||||
def.field_representing_type_info(self.tcx(), args)
|
||||
// NOTE: these bounds have to be kept in sync with the definition of the `Field` trait
|
||||
// in `library/core/src/field.rs` as well as the new trait solver `fn
|
||||
// consider_builtin_field_candidate` in
|
||||
// `compiler/rustc_next_trait_solver/src/solve/trait_goals.rs`.
|
||||
&& match self.infcx.evaluate_obligation(&PredicateObligation::new(
|
||||
self.tcx(),
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
TraitRef::new(
|
||||
self.tcx(),
|
||||
self.tcx().require_lang_item(LangItem::Sized, DUMMY_SP),
|
||||
[base],
|
||||
),
|
||||
)) {
|
||||
Ok(res) if res.must_apply_modulo_regions() => true,
|
||||
_ => false,
|
||||
}
|
||||
&& match self.infcx.evaluate_obligation(&PredicateObligation::new(
|
||||
self.tcx(),
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
TraitRef::new(
|
||||
self.tcx(),
|
||||
self.tcx().require_lang_item(LangItem::Sized, DUMMY_SP),
|
||||
[ty],
|
||||
),
|
||||
)) {
|
||||
Ok(res) if res.must_apply_modulo_regions() => true,
|
||||
_ => false,
|
||||
}
|
||||
&& match base.kind() {
|
||||
ty::Adt(def, _) => def.is_struct() && !def.repr().packed(),
|
||||
ty::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
{
|
||||
candidates.vec.push(BuiltinCandidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ fn confirm_builtin_candidate(
|
||||
Some(
|
||||
LangItem::Destruct
|
||||
| LangItem::DiscriminantKind
|
||||
| LangItem::Field
|
||||
| LangItem::FnPtrTrait
|
||||
| LangItem::PointeeTrait
|
||||
| LangItem::Tuple
|
||||
|
||||
@@ -386,6 +386,22 @@ fn resolve_associated_item<'tcx>(
|
||||
assert_eq!(name, sym::transmute);
|
||||
let args = tcx.erase_and_anonymize_regions(rcvr_args);
|
||||
Some(ty::Instance::new_raw(trait_item_id, args))
|
||||
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::Field) {
|
||||
if tcx.is_lang_item(trait_item_id, LangItem::FieldOffset) {
|
||||
let self_ty = trait_ref.self_ty();
|
||||
match self_ty.kind() {
|
||||
ty::Adt(def, _) if def.is_field_representing_type() => {}
|
||||
_ => bug!("expected field representing type, found {self_ty}"),
|
||||
}
|
||||
Some(Instance {
|
||||
def: ty::InstanceKind::Item(
|
||||
tcx.lang_items().get(LangItem::FieldOffset).unwrap(),
|
||||
),
|
||||
args: rcvr_args,
|
||||
})
|
||||
} else {
|
||||
bug!("unexpected associated associated item")
|
||||
}
|
||||
} else {
|
||||
Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ derive-where = "1.2.7"
|
||||
ena = "0.14.4"
|
||||
indexmap = "2.0.0"
|
||||
rustc-hash = "2.0.0"
|
||||
rustc_abi = { path = "../rustc_abi", default-features = false }
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_error_messages = { path = "../rustc_error_messages", optional = true }
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{AdtDestructorKind, SizedTraitKind};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, ClauseKind, CollectAndApply, Interner, PredicateKind, UpcastFrom};
|
||||
use crate::{
|
||||
self as ty, ClauseKind, CollectAndApply, FieldInfo, Interner, PredicateKind, UpcastFrom,
|
||||
};
|
||||
|
||||
pub trait Ty<I: Interner<Ty = Self>>:
|
||||
Copy
|
||||
@@ -577,6 +579,8 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
|
||||
fn is_struct(self) -> bool;
|
||||
|
||||
fn is_packed(self) -> bool;
|
||||
|
||||
/// Returns the type of the struct tail.
|
||||
///
|
||||
/// Expects the `AdtDef` to be a struct. If it is not, then this will panic.
|
||||
@@ -586,6 +590,12 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
|
||||
fn is_manually_drop(self) -> bool;
|
||||
|
||||
fn field_representing_type_info(
|
||||
self,
|
||||
interner: I,
|
||||
args: I::GenericArgs,
|
||||
) -> Option<FieldInfo<I>>;
|
||||
|
||||
// FIXME: perhaps use `all_fields` and expose `FieldDef`.
|
||||
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ pub enum SolverLangItem {
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FieldBase,
|
||||
FieldType,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
@@ -36,6 +38,7 @@ pub enum SolverTraitLangItem {
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
Field,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
|
||||
|
||||
@@ -440,3 +441,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldInfo<I: Interner> {
|
||||
pub base: I::Ty,
|
||||
pub ty: I::Ty,
|
||||
pub variant: Option<I::Symbol>,
|
||||
pub variant_idx: VariantIdx,
|
||||
pub name: I::Symbol,
|
||||
pub field_idx: FieldIdx,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
//! Field Reflection
|
||||
|
||||
use crate::marker::PhantomData;
|
||||
|
||||
/// Field Representing Type
|
||||
#[unstable(feature = "field_representing_type_raw", issue = "none")]
|
||||
#[lang = "field_representing_type"]
|
||||
#[expect(missing_debug_implementations)]
|
||||
#[fundamental]
|
||||
pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
|
||||
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Send
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
|
||||
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Sync
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Copy
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Clone
|
||||
for FieldRepresentingType<T, VARIANT, FIELD>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands to the field representing type of the given field.
|
||||
///
|
||||
/// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the
|
||||
/// variant must also be specified. Only a single field is supported.
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[allow_internal_unstable(field_representing_type_raw, builtin_syntax)]
|
||||
// NOTE: when stabilizing this macro, we can never add new trait impls for `FieldRepresentingType`,
|
||||
// since it is `#[fundamental]` and thus could break users of this macro, since the compiler expands
|
||||
// it to `FieldRepresentingType<...>`. Thus stabilizing this requires careful thought about the
|
||||
// completeness of the trait impls for `FieldRepresentingType`.
|
||||
pub macro field_of($Container:ty, $($fields:expr)+ $(,)?) {
|
||||
builtin # field_of($Container, $($fields)+)
|
||||
}
|
||||
|
||||
/// Type representing a field of a `struct`, `union`, `enum` variant or tuple.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Given a valid value of type `Self::Base`, there exists a valid value of type `Self::Type` at
|
||||
/// byte offset `OFFSET`
|
||||
#[lang = "field"]
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[rustc_deny_explicit_impl]
|
||||
#[rustc_dyn_incompatible_trait]
|
||||
// NOTE: the compiler provides the impl of `Field` for `FieldRepresentingType` when it can guarantee
|
||||
// the safety requirements of this trait. It also has to manually add the correct trait bounds on
|
||||
// associated types (and the `Self` type). Thus any changes to the bounds here must be reflected in
|
||||
// the old and new trait solver:
|
||||
// - `fn assemble_candidates_for_field_trait` in
|
||||
// `compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs`, and
|
||||
// - `fn consider_builtin_field_candidate` in
|
||||
// `compiler/rustc_next_trait_solver/src/solve/trait_goals.rs`.
|
||||
pub unsafe trait Field: Send + Sync + Copy {
|
||||
/// The type of the base where this field exists in.
|
||||
#[lang = "field_base"]
|
||||
type Base;
|
||||
|
||||
/// The type of the field.
|
||||
#[lang = "field_type"]
|
||||
type Type;
|
||||
|
||||
/// The offset of the field in bytes.
|
||||
#[lang = "field_offset"]
|
||||
const OFFSET: usize = crate::intrinsics::field_offset::<Self>();
|
||||
}
|
||||
@@ -2812,6 +2812,20 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
|
||||
#[lang = "offset_of"]
|
||||
pub const fn offset_of<T: PointeeSized>(variant: u32, field: u32) -> usize;
|
||||
|
||||
/// The offset of a field queried by its field representing type.
|
||||
///
|
||||
/// Returns the offset of the field represented by `F`. This function essentially does the same as
|
||||
/// the [`offset_of`] intrinsic, but expects the field to be represented by a generic rather than
|
||||
/// the variant and field indices. This also is a safe intrinsic and can only be evaluated at
|
||||
/// compile-time, so it should only appear in constants or inline const blocks.
|
||||
///
|
||||
/// There should be no need to call this intrinsic manually, as its value is used to define
|
||||
/// [`Field::OFFSET`](crate::field::Field::OFFSET), which is publicly accessible.
|
||||
#[rustc_intrinsic]
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
#[rustc_const_unstable(feature = "field_projections", issue = "145383")]
|
||||
pub const fn field_offset<F: crate::field::Field>() -> usize;
|
||||
|
||||
/// Returns the number of variants of the type `T` cast to a `usize`;
|
||||
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
|
||||
///
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(f16)]
|
||||
#![feature(f128)]
|
||||
#![feature(field_projections)]
|
||||
#![feature(freeze_impls)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(funnel_shifts)]
|
||||
@@ -274,6 +275,8 @@ pub mod autodiff {
|
||||
pub mod convert;
|
||||
pub mod default;
|
||||
pub mod error;
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
pub mod field;
|
||||
pub mod index;
|
||||
pub mod marker;
|
||||
pub mod ops;
|
||||
|
||||
+32
-29
@@ -15,22 +15,19 @@
|
||||
//! The precise rules for validity are not determined yet. The guarantees that are
|
||||
//! provided at this point are very minimal:
|
||||
//!
|
||||
//! * For memory accesses of [size zero][zst], *every* pointer is valid, including the [null]
|
||||
//! pointer. The following points are only concerned with non-zero-sized accesses.
|
||||
//! * A [null] pointer is *never* valid.
|
||||
//! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be
|
||||
//! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocation]
|
||||
//! it is derived from; a pointer is dereferenceable if the memory range of the given size
|
||||
//! starting at the pointer is entirely contained within the bounds of that allocation. Note
|
||||
//! * A [null] pointer is *never* valid for reads/writes.
|
||||
//! * For memory accesses of [size zero][zst], *every* non-null pointer is valid for reads/writes.
|
||||
//! The following points are only concerned with non-zero-sized accesses.
|
||||
//! * For a pointer to be valid for reads/writes, it is necessary, but not always sufficient, that
|
||||
//! the pointer be *dereferenceable*. The [provenance] of the pointer is used to determine which
|
||||
//! [allocation] it is derived from; a pointer is dereferenceable if the memory range of the given
|
||||
//! size starting at the pointer is entirely contained within the bounds of that allocation. Note
|
||||
//! that in Rust, every (stack-allocated) variable is considered a separate allocation.
|
||||
//! * All accesses performed by functions in this module are *non-atomic* in the sense
|
||||
//! of [atomic operations] used to synchronize between threads. This means it is
|
||||
//! undefined behavior to perform two concurrent accesses to the same location from different
|
||||
//! threads unless both accesses only read from memory. Notice that this explicitly
|
||||
//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot
|
||||
//! be used for inter-thread synchronization, regardless of whether they are acting on
|
||||
//! Rust memory or not.
|
||||
//! * The result of casting a reference to a pointer is valid for as long as the
|
||||
//! threads unless both accesses only read from memory.
|
||||
//! * The result of casting a reference to a pointer is valid for reads/writes for as long as the
|
||||
//! underlying allocation is live and no reference (just raw pointers) is used to
|
||||
//! access the same memory. That is, reference and pointer accesses cannot be
|
||||
//! interleaved.
|
||||
@@ -41,6 +38,13 @@
|
||||
//! information, see the [book] as well as the section in the reference devoted
|
||||
//! to [undefined behavior][ub].
|
||||
//!
|
||||
//! Note that some operations such as [`read`] and [`write`][`write()`] do allow null pointers if
|
||||
//! the total size of the access is zero. However, other operations internally convert pointers into
|
||||
//! references. Therefore, the general notion of "valid for reads/writes" excludes null pointers,
|
||||
//! and the specific operations that permit null pointers mention that as an exception. Furthermore,
|
||||
//! [`read_volatile`] and [`write_volatile`] can be used in even more situations; see their
|
||||
//! documentation for details.
|
||||
//!
|
||||
//! We say that a pointer is "dangling" if it is not valid for any non-zero-sized accesses. This
|
||||
//! means out-of-bounds pointers, pointers to freed memory, null pointers, and pointers created with
|
||||
//! [`NonNull::dangling`] are all dangling.
|
||||
@@ -450,9 +454,9 @@
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
|
||||
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes or that number must be 0.
|
||||
///
|
||||
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
|
||||
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes or that number must be 0.
|
||||
///
|
||||
/// * Both `src` and `dst` must be properly aligned.
|
||||
///
|
||||
@@ -568,11 +572,11 @@
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
|
||||
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes or that number must be 0.
|
||||
///
|
||||
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
|
||||
/// when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
|
||||
/// overlap, the `dst` pointer must not be invalidated by `src` reads.)
|
||||
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes or that number must be 0,
|
||||
/// and `dst` must remain valid even when `src` is read for `count * size_of::<T>()` bytes. (This
|
||||
/// means if the memory ranges overlap, the `dst` pointer must not be invalidated by `src` reads.)
|
||||
///
|
||||
/// * Both `src` and `dst` must be properly aligned.
|
||||
///
|
||||
@@ -1508,7 +1512,7 @@ macro_rules! swap_prefix {
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `dst` must be [valid] for both reads and writes.
|
||||
/// * `dst` must be [valid] for both reads and writes or `T` must be a ZST.
|
||||
///
|
||||
/// * `dst` must be properly aligned.
|
||||
///
|
||||
@@ -1555,10 +1559,9 @@ macro_rules! swap_prefix {
|
||||
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
|
||||
);
|
||||
if T::IS_ZST {
|
||||
// `dst` may be valid for read and writes while also being null, in which case we cannot
|
||||
// call `mem::replace`. However, we also don't have to actually do anything since there
|
||||
// isn't actually any data to be copied anyway. All values of type `T` are
|
||||
// bit-identical, so we can just return `src` here.
|
||||
// If `T` is a ZST, `dst` is allowed to be null. However, we also don't have to actually
|
||||
// do anything since there isn't actually any data to be copied anyway. All values of
|
||||
// type `T` are bit-identical, so we can just return `src` here.
|
||||
return src;
|
||||
}
|
||||
mem::replace(&mut *dst, src)
|
||||
@@ -1572,7 +1575,7 @@ macro_rules! swap_prefix {
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `src` must be [valid] for reads.
|
||||
/// * `src` must be [valid] for reads or `T` must be a ZST.
|
||||
///
|
||||
/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
|
||||
/// case.
|
||||
@@ -1824,7 +1827,7 @@ macro_rules! swap_prefix {
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `dst` must be [valid] for writes.
|
||||
/// * `dst` must be [valid] for writes or `T` must be a ZST.
|
||||
///
|
||||
/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
|
||||
/// case.
|
||||
@@ -2047,8 +2050,8 @@ macro_rules! swap_prefix {
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust
|
||||
/// allocations and reading from that memory must:
|
||||
/// * `src` must be either [valid] for reads, or `T` must be a ZST, or `src` must point to memory
|
||||
/// outside of all Rust allocations and reading from that memory must:
|
||||
/// - not trap, and
|
||||
/// - not cause any memory inside a Rust allocation to be modified.
|
||||
///
|
||||
@@ -2135,8 +2138,8 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||
///
|
||||
/// Behavior is undefined if any of the following conditions are violated:
|
||||
///
|
||||
/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust
|
||||
/// allocations and writing to that memory must:
|
||||
/// * `dst` must be either [valid] for writes, or `T` must be a ZST, or `dst` must point to memory
|
||||
/// outside of all Rust allocations and writing to that memory must:
|
||||
/// - not trap, and
|
||||
/// - not cause any memory inside a Rust allocation to be modified.
|
||||
///
|
||||
|
||||
@@ -495,6 +495,8 @@
|
||||
pub use core::convert;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::default;
|
||||
#[unstable(feature = "field_projections", issue = "145383")]
|
||||
pub use core::field;
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
pub use core::future;
|
||||
#[stable(feature = "core_hint", since = "1.27.0")]
|
||||
|
||||
@@ -29,19 +29,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1
|
||||
ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS="1"
|
||||
|
||||
# llvm.use-linker conflicts with downloading CI LLVM
|
||||
ENV NO_DOWNLOAD_CI_LLVM 1
|
||||
ENV NO_DOWNLOAD_CI_LLVM="1"
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=aarch64-unknown-linux-gnu \
|
||||
ENV RUST_CONFIGURE_ARGS="--build=aarch64-unknown-linux-gnu \
|
||||
--enable-debug \
|
||||
--enable-lld \
|
||||
--set llvm.use-linker=lld \
|
||||
--set target.aarch64-unknown-linux-gnu.linker=clang \
|
||||
--set target.aarch64-unknown-linux-gnu.cc=clang \
|
||||
--set target.aarch64-unknown-linux-gnu.cxx=clang++
|
||||
--set target.aarch64-unknown-linux-gnu.cxx=clang++"
|
||||
|
||||
# This job appears to be checking two separate things:
|
||||
# - That we can build the compiler with `--enable-debug`
|
||||
@@ -52,6 +51,5 @@ ENV RUST_CONFIGURE_ARGS \
|
||||
# Currently we only run the subset of tests with "clang" in their name.
|
||||
# - See also FIXME(#132034)
|
||||
|
||||
ENV SCRIPT \
|
||||
python3 ../x.py --stage 2 build && \
|
||||
python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo
|
||||
ENV SCRIPT="python3 ../x.py --stage 2 build && \
|
||||
python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo"
|
||||
|
||||
@@ -1809,6 +1809,14 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||
}
|
||||
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
|
||||
TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
|
||||
TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
|
||||
let field_str = if let Some(variant) = variant {
|
||||
format!("{variant}.{field}")
|
||||
} else {
|
||||
format!("{field}")
|
||||
};
|
||||
Type::FieldOf(Box::new(clean_ty(ty, cx)), field_str.into())
|
||||
}
|
||||
TyKind::Array(ty, const_arg) => {
|
||||
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
||||
// as we currently do not supply the parent generics to anonymous constants
|
||||
@@ -2701,7 +2709,29 @@ fn add_without_unwanted_attributes<'hir>(
|
||||
}
|
||||
hir::Attribute::Parsed(AttributeKind::Doc(box d)) => {
|
||||
// Remove attributes from `normal` that should not be inherited by `use` re-export.
|
||||
let DocAttribute { hidden, inline, cfg, .. } = d;
|
||||
let DocAttribute {
|
||||
aliases,
|
||||
hidden,
|
||||
inline,
|
||||
cfg,
|
||||
auto_cfg: _,
|
||||
auto_cfg_change: _,
|
||||
fake_variadic: _,
|
||||
keyword: _,
|
||||
attribute: _,
|
||||
masked: _,
|
||||
notable_trait: _,
|
||||
search_unbox: _,
|
||||
html_favicon_url: _,
|
||||
html_logo_url: _,
|
||||
html_playground_url: _,
|
||||
html_root_url: _,
|
||||
html_no_source: _,
|
||||
issue_tracker_base_url: _,
|
||||
rust_logo: _,
|
||||
test_attrs: _,
|
||||
no_crate_inject: _,
|
||||
} = d;
|
||||
let mut attr = DocAttribute::default();
|
||||
if is_inline {
|
||||
attr.cfg = cfg.clone();
|
||||
@@ -2709,6 +2739,7 @@ fn add_without_unwanted_attributes<'hir>(
|
||||
attr.inline = inline.clone();
|
||||
attr.hidden = hidden.clone();
|
||||
}
|
||||
attr.aliases = aliases.clone();
|
||||
attrs.push((
|
||||
Cow::Owned(hir::Attribute::Parsed(AttributeKind::Doc(Box::new(attr)))),
|
||||
import_parent,
|
||||
|
||||
@@ -1349,6 +1349,7 @@ pub(crate) enum Type {
|
||||
/// The `String` field is a stringified version of the array's length parameter.
|
||||
Array(Box<Type>, Box<str>),
|
||||
Pat(Box<Type>, Box<str>),
|
||||
FieldOf(Box<Type>, Box<str>),
|
||||
/// A raw pointer type: `*const i32`, `*mut i32`
|
||||
RawPointer(Mutability, Box<Type>),
|
||||
/// A reference type: `&i32`, `&'a mut Foo`
|
||||
@@ -1562,6 +1563,7 @@ pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
|
||||
Slice(..) => PrimitiveType::Slice,
|
||||
Array(..) => PrimitiveType::Array,
|
||||
Type::Pat(..) => PrimitiveType::Pat,
|
||||
Type::FieldOf(..) => PrimitiveType::FieldOf,
|
||||
RawPointer(..) => PrimitiveType::RawPointer,
|
||||
QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
|
||||
Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
|
||||
@@ -1609,6 +1611,7 @@ pub(crate) enum PrimitiveType {
|
||||
Slice,
|
||||
Array,
|
||||
Pat,
|
||||
FieldOf,
|
||||
Tuple,
|
||||
Unit,
|
||||
RawPointer,
|
||||
@@ -1764,6 +1767,7 @@ pub(crate) fn as_sym(&self) -> Symbol {
|
||||
Char => sym::char,
|
||||
Array => sym::array,
|
||||
Pat => sym::pat,
|
||||
FieldOf => sym::field_of,
|
||||
Slice => sym::slice,
|
||||
Tuple => sym::tuple,
|
||||
Unit => sym::unit,
|
||||
|
||||
@@ -967,6 +967,11 @@ fn fmt_type(
|
||||
fmt::Display::fmt(&print_type(t, cx), f)?;
|
||||
write!(f, " is {pat}")
|
||||
}
|
||||
clean::Type::FieldOf(t, field) => {
|
||||
write!(f, "field_of!(")?;
|
||||
fmt::Display::fmt(&print_type(t, cx), f)?;
|
||||
write!(f, ", {field})")
|
||||
}
|
||||
clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link(
|
||||
f,
|
||||
PrimitiveType::Array,
|
||||
|
||||
@@ -2049,6 +2049,7 @@ fn get_index_type_id(
|
||||
}
|
||||
// Not supported yet
|
||||
clean::Type::Pat(..)
|
||||
| clean::Type::FieldOf(..)
|
||||
| clean::Generic(_)
|
||||
| clean::SelfTy
|
||||
| clean::ImplTrait(_)
|
||||
|
||||
@@ -579,6 +579,8 @@ fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self {
|
||||
type_: Box::new(t.into_json(renderer)),
|
||||
__pat_unstable_do_not_use: p.to_string(),
|
||||
},
|
||||
// FIXME(FRTs): implement
|
||||
clean::Type::FieldOf(..) => todo!(),
|
||||
ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)),
|
||||
Infer => Type::Infer,
|
||||
RawPointer(mutability, type_) => Type::RawPointer {
|
||||
|
||||
@@ -852,6 +852,7 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
|
||||
| TyKind::Ptr(_)
|
||||
| TyKind::FnPtr(_)
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::FieldOf(..)
|
||||
| TyKind::Never
|
||||
| TyKind::Tup(_)
|
||||
| TyKind::Path(_) => Self::Deref,
|
||||
|
||||
@@ -531,6 +531,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
|
||||
|
||||
// experimental
|
||||
| TyKind::Pat(..)
|
||||
| TyKind::FieldOf(..)
|
||||
|
||||
// unused
|
||||
| TyKind::CVarArgs
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind,
|
||||
LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind,
|
||||
Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
|
||||
TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind,
|
||||
TyFieldPath, TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
@@ -1529,6 +1529,13 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
|
||||
self.hash_ty(ty);
|
||||
self.hash_ty_pat(pat);
|
||||
},
|
||||
TyKind::FieldOf(base, TyFieldPath { variant, field }) => {
|
||||
self.hash_ty(base);
|
||||
if let Some(variant) = variant {
|
||||
self.hash_name(variant.name);
|
||||
}
|
||||
self.hash_name(field.name);
|
||||
},
|
||||
TyKind::Ptr(mut_ty) => {
|
||||
self.hash_ty(mut_ty.ty);
|
||||
mut_ty.mutbl.hash(&mut self.s);
|
||||
|
||||
@@ -257,7 +257,6 @@ macro_rules! generate {
|
||||
f64_legacy_const_nan,
|
||||
f64_legacy_const_neg_infinity,
|
||||
f64_legacy_const_radix,
|
||||
field,
|
||||
file_options,
|
||||
filter,
|
||||
filter_map,
|
||||
|
||||
@@ -328,11 +328,7 @@ fn check_ptr_ptr_cast(
|
||||
//
|
||||
// Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
|
||||
// and is unaffected by this check.
|
||||
(Some(src_principal), Some(dst_principal)) => {
|
||||
if src_principal == dst_principal {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
(Some(src_principal), Some(_)) => {
|
||||
// We need to reconstruct trait object types.
|
||||
// `m_src` and `m_dst` won't work for us here because they will potentially
|
||||
// contain wrappers, which we do not care about.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use ide_db::FileId;
|
||||
use syntax::{
|
||||
AstNode, TextRange,
|
||||
ast::{self, HasVisibility as _, edit_in_place::HasVisibilityEdit, make},
|
||||
ast::{self, HasVisibility as _, syntax_factory::SyntaxFactory},
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, Assists};
|
||||
@@ -59,10 +59,12 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
|
||||
let (vis_owner, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?;
|
||||
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
|
||||
let missing_visibility = if current_module.krate(ctx.db()) == target_module.krate(ctx.db()) {
|
||||
make::visibility_pub_crate()
|
||||
make.visibility_pub_crate()
|
||||
} else {
|
||||
make::visibility_pub()
|
||||
make.visibility_pub()
|
||||
};
|
||||
|
||||
let assist_label = match target_name {
|
||||
@@ -75,15 +77,36 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
}
|
||||
};
|
||||
|
||||
acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |edit| {
|
||||
edit.edit_file(target_file);
|
||||
acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |builder| {
|
||||
let mut editor = builder.make_editor(vis_owner.syntax());
|
||||
|
||||
let vis_owner = edit.make_mut(vis_owner);
|
||||
vis_owner.set_visibility(Some(missing_visibility.clone_for_update()));
|
||||
if let Some(current_visibility) = vis_owner.visibility() {
|
||||
editor.replace(current_visibility.syntax(), missing_visibility.syntax());
|
||||
} else {
|
||||
let vis_before = vis_owner
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.find(|it| {
|
||||
!matches!(
|
||||
it.kind(),
|
||||
syntax::SyntaxKind::WHITESPACE
|
||||
| syntax::SyntaxKind::COMMENT
|
||||
| syntax::SyntaxKind::ATTR
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| vis_owner.syntax().first_child_or_token().unwrap());
|
||||
|
||||
if let Some((cap, vis)) = ctx.config.snippet_cap.zip(vis_owner.visibility()) {
|
||||
edit.add_tabstop_before(cap, vis);
|
||||
editor.insert_all(
|
||||
syntax::syntax_editor::Position::before(vis_before),
|
||||
vec![missing_visibility.syntax().clone().into(), make.whitespace(" ").into()],
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(cap) = ctx.config.snippet_cap {
|
||||
editor.add_annotation(missing_visibility.syntax(), builder.make_tabstop_before(cap));
|
||||
}
|
||||
|
||||
builder.add_file_edits(target_file, editor);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use syntax::{
|
||||
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
|
||||
T,
|
||||
ast::{self, AstNode, HasAttrs, edit::IndentLevel, make},
|
||||
ast::{self, AstNode, HasAttrs, edit::IndentLevel, syntax_factory::SyntaxFactory},
|
||||
syntax_editor::{Element, Position},
|
||||
};
|
||||
|
||||
@@ -42,13 +42,15 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
|
||||
};
|
||||
|
||||
acc.add(AssistId::generate("generate_derive"), "Add `#[derive]`", target, |edit| {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
|
||||
match derive_attr {
|
||||
None => {
|
||||
let derive = make::attr_outer(make::meta_token_tree(
|
||||
make::ext::ident_path("derive"),
|
||||
make::token_tree(T!['('], vec![]).clone_for_update(),
|
||||
))
|
||||
.clone_for_update();
|
||||
let derive =
|
||||
make.attr_outer(make.meta_token_tree(
|
||||
make.ident_path("derive"),
|
||||
make.token_tree(T!['('], vec![]),
|
||||
));
|
||||
|
||||
let mut editor = edit.make_editor(nominal.syntax());
|
||||
let indent = IndentLevel::from_node(nominal.syntax());
|
||||
@@ -57,11 +59,12 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
|
||||
.children_with_tokens()
|
||||
.find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
|
||||
.map_or(Position::first_child_of(nominal.syntax()), Position::before);
|
||||
|
||||
editor.insert_all(
|
||||
after_attrs_and_comments,
|
||||
vec![
|
||||
derive.syntax().syntax_element(),
|
||||
make::tokens::whitespace(&format!("\n{indent}")).syntax_element(),
|
||||
make.whitespace(&format!("\n{indent}")).syntax_element(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -72,7 +75,9 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
|
||||
.expect("failed to get token tree out of Meta")
|
||||
.r_paren_token()
|
||||
.expect("make::attr_outer was expected to have a R_PAREN");
|
||||
|
||||
let tabstop_before = edit.make_tabstop_before(cap);
|
||||
|
||||
editor.add_annotation(delimiter, tabstop_before);
|
||||
edit.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
}
|
||||
|
||||
+55
-19
@@ -57,7 +57,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
|
||||
let if_exprs = successors(Some(if_expr.clone()), |expr| match expr.else_branch()? {
|
||||
ast::ElseBranch::IfExpr(expr) => Some(expr),
|
||||
ast::ElseBranch::Block(block) => {
|
||||
let block = unwrap_trivial_block(block).clone_for_update();
|
||||
let block = unwrap_trivial_block(block);
|
||||
else_block = Some(block.reset_indent().indent(IndentLevel(1)));
|
||||
None
|
||||
}
|
||||
@@ -91,7 +91,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
|
||||
guard
|
||||
};
|
||||
|
||||
let body = if_expr.then_branch()?.clone_for_update().indent(IndentLevel(1));
|
||||
let body = if_expr.then_branch()?.indent(IndentLevel(1));
|
||||
cond_bodies.push((cond, guard, body));
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
|
||||
let make_match_arm =
|
||||
|(pat, guard, body): (_, Option<ast::Expr>, ast::BlockExpr)| {
|
||||
// Dedent from original position, then indent for match arm
|
||||
let body = body.dedent(indent).indent(IndentLevel::single());
|
||||
let body = body.dedent(indent);
|
||||
let body = unwrap_trivial_block(body);
|
||||
match (pat, guard.map(|it| make.match_guard(it))) {
|
||||
(Some(pat), guard) => make.match_arm(pat, guard, body),
|
||||
@@ -127,8 +127,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
|
||||
}
|
||||
};
|
||||
let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
|
||||
let match_expr =
|
||||
make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms)).indent(indent);
|
||||
let expr = scrutinee_to_be_expr.reset_indent();
|
||||
let match_expr = make.expr_match(expr, make.match_arm_list(arms)).indent(indent);
|
||||
match_expr.into()
|
||||
};
|
||||
|
||||
@@ -246,7 +246,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
|
||||
first_arm.guard(),
|
||||
second_arm.guard(),
|
||||
)?;
|
||||
let scrutinee = match_expr.expr()?;
|
||||
let scrutinee = match_expr.expr()?.reset_indent();
|
||||
let guard = guard.and_then(|it| it.condition());
|
||||
|
||||
let let_ = match &if_let_pat {
|
||||
@@ -293,10 +293,8 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
|
||||
} else {
|
||||
condition
|
||||
};
|
||||
let then_expr =
|
||||
then_expr.clone_for_update().reset_indent().indent(IndentLevel::single());
|
||||
let else_expr =
|
||||
else_expr.clone_for_update().reset_indent().indent(IndentLevel::single());
|
||||
let then_expr = then_expr.reset_indent();
|
||||
let else_expr = else_expr.reset_indent();
|
||||
let then_block = make_block_expr(then_expr);
|
||||
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
||||
let if_let_expr = make
|
||||
@@ -956,7 +954,9 @@ fn nested_indent() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
$0if let Ok(rel_path) = path.strip_prefix(root_path) {
|
||||
$0if let Ok(rel_path) = path.strip_prefix(root_path)
|
||||
.and(x)
|
||||
{
|
||||
let rel_path = RelativePathBuf::from_path(rel_path)
|
||||
.ok()?;
|
||||
Some((*id, rel_path))
|
||||
@@ -971,7 +971,8 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
match path.strip_prefix(root_path) {
|
||||
match path.strip_prefix(root_path)
|
||||
.and(x) {
|
||||
Ok(rel_path) => {
|
||||
let rel_path = RelativePathBuf::from_path(rel_path)
|
||||
.ok()?;
|
||||
@@ -993,7 +994,9 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
$0if let Ok(rel_path) = path.strip_prefix(root_path) {
|
||||
$0if let Ok(rel_path) = path.strip_prefix(root_path)
|
||||
.and(x)
|
||||
{
|
||||
Foo {
|
||||
x: 1
|
||||
}
|
||||
@@ -1008,7 +1011,8 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
match path.strip_prefix(root_path) {
|
||||
match path.strip_prefix(root_path)
|
||||
.and(x) {
|
||||
Ok(rel_path) => {
|
||||
Foo {
|
||||
x: 1
|
||||
@@ -1023,7 +1027,33 @@ fn main() {
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
);
|
||||
|
||||
check_assist(
|
||||
replace_if_let_with_match,
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
$0if true
|
||||
&& false
|
||||
{
|
||||
foo()
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
match true
|
||||
&& false {
|
||||
true => foo(),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1878,7 +1908,9 @@ fn nested_indent_match_to_if_let() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
$0match path.strip_prefix(root_path) {
|
||||
$0match path.strip_prefix(root_path)
|
||||
.and(x)
|
||||
{
|
||||
Ok(rel_path) => Foo {
|
||||
x: 2
|
||||
}
|
||||
@@ -1892,7 +1924,8 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
if let Ok(rel_path) = path.strip_prefix(root_path) {
|
||||
if let Ok(rel_path) = path.strip_prefix(root_path)
|
||||
.and(x) {
|
||||
Foo {
|
||||
x: 2
|
||||
}
|
||||
@@ -1911,7 +1944,9 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
$0match path.strip_prefix(root_path) {
|
||||
$0match path.strip_prefix(root_path)
|
||||
.and(x)
|
||||
{
|
||||
Ok(rel_path) => {
|
||||
let rel_path = RelativePathBuf::from_path(rel_path)
|
||||
.ok()?;
|
||||
@@ -1929,7 +1964,8 @@ fn main() {
|
||||
r#"
|
||||
fn main() {
|
||||
if true {
|
||||
if let Ok(rel_path) = path.strip_prefix(root_path) {
|
||||
if let Ok(rel_path) = path.strip_prefix(root_path)
|
||||
.and(x) {
|
||||
let rel_path = RelativePathBuf::from_path(rel_path)
|
||||
.ok()?;
|
||||
Some((*id, rel_path))
|
||||
|
||||
@@ -95,7 +95,7 @@ pub(crate) fn complete_pattern(
|
||||
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
|
||||
{
|
||||
acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
|
||||
true
|
||||
false
|
||||
}
|
||||
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
||||
hir::ModuleDef::Const(..) => refutable,
|
||||
|
||||
@@ -122,7 +122,6 @@ fn foo() {
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
ev TupleV
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
@@ -159,8 +158,6 @@ fn foo(foo: Foo) { match foo { Foo { x: $0 } } }
|
||||
expect![[r#"
|
||||
en Bar
|
||||
st Foo
|
||||
ev Nil
|
||||
ev Value
|
||||
bn Foo {…} Foo { x$1 }$0
|
||||
bn Nil Nil$0
|
||||
bn Value Value$0
|
||||
@@ -189,7 +186,6 @@ fn foo() {
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
ev Variant
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn Variant Variant$0
|
||||
@@ -354,6 +350,34 @@ fn func() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_unqualified() {
|
||||
check_with_base_items(
|
||||
r#"
|
||||
use Enum::*;
|
||||
fn func() {
|
||||
if let $0 = unknown {}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
bn Record {…} Record { field$1 }$0
|
||||
bn RecordV {…} RecordV { field$1 }$0
|
||||
bn Tuple(…) Tuple($1)$0
|
||||
bn TupleV(…) TupleV($1)$0
|
||||
bn UnitV UnitV$0
|
||||
kw mut
|
||||
kw ref
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_in_record_field_pat() {
|
||||
check(
|
||||
|
||||
@@ -61,8 +61,6 @@ fn foo(baz: Baz) {
|
||||
en Baz
|
||||
en Result
|
||||
md core
|
||||
ev Err
|
||||
ev Ok
|
||||
bn Baz::Bar Baz::Bar$0
|
||||
bn Baz::Foo Baz::Foo$0
|
||||
bn Err(…) Err($1)$0
|
||||
@@ -89,10 +87,6 @@ fn foo(baz: Baz) {
|
||||
en Baz
|
||||
en Result
|
||||
md core
|
||||
ev Bar
|
||||
ev Err
|
||||
ev Foo
|
||||
ev Ok
|
||||
bn Bar Bar$0
|
||||
bn Err(…) Err($1)$0
|
||||
bn Foo Foo$0
|
||||
|
||||
@@ -517,11 +517,13 @@ trait Trait<'a> {}
|
||||
|
||||
fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
|
||||
x as _
|
||||
//^^^^^^ error: cannot add auto trait to dyn bound via pointer cast
|
||||
}
|
||||
|
||||
// (to test diagnostic list formatting)
|
||||
fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
|
||||
x as _
|
||||
//^^^^^^ error: cannot add auto trait to dyn bound via pointer cast
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
use itertools::Itertools;
|
||||
use proc_macro_api::{
|
||||
MacroDylib, ProcMacroClient,
|
||||
bidirectional_protocol::msg::{SubRequest, SubResponse},
|
||||
bidirectional_protocol::msg::{ParentSpan, SubRequest, SubResponse},
|
||||
};
|
||||
use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
|
||||
use span::{Span, SpanAnchor, SyntaxContext};
|
||||
@@ -659,6 +659,44 @@ fn expand(
|
||||
ctx: current_span.ctx.into_u32(),
|
||||
})
|
||||
}
|
||||
SubRequest::SpanParent { file_id, ast_id, start, end, ctx } => {
|
||||
let span = Span {
|
||||
range: TextRange::new(TextSize::from(start), TextSize::from(end)),
|
||||
anchor: SpanAnchor {
|
||||
file_id: span::EditionedFileId::from_raw(file_id),
|
||||
ast_id: span::ErasedFileAstId::from_raw(ast_id),
|
||||
},
|
||||
// SAFETY: We only receive spans from the server. If someone mess up the communication UB can happen,
|
||||
// but that will be their problem.
|
||||
ctx: unsafe { SyntaxContext::from_u32(ctx) },
|
||||
};
|
||||
|
||||
if let Some(macro_call_id) = span.ctx.outer_expn(db) {
|
||||
let macro_call_loc = db.lookup_intern_macro_call(macro_call_id.into());
|
||||
|
||||
let call_site_file = macro_call_loc.kind.file_id();
|
||||
let call_site_ast_id = macro_call_loc.kind.erased_ast_id();
|
||||
|
||||
if let Some(editioned_file_id) = call_site_file.file_id() {
|
||||
let range = db
|
||||
.ast_id_map(editioned_file_id.into())
|
||||
.get_erased(call_site_ast_id)
|
||||
.text_range();
|
||||
|
||||
let parent_span = Some(ParentSpan {
|
||||
file_id: editioned_file_id.editioned_file_id(db).as_u32(),
|
||||
ast_id: span::ROOT_ERASED_FILE_AST_ID.into_raw(),
|
||||
start: u32::from(range.start()),
|
||||
end: u32::from(range.end()),
|
||||
ctx: macro_call_loc.ctxt.into_u32(),
|
||||
});
|
||||
|
||||
return Ok(SubResponse::SpanParentResult { parent_span });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(SubResponse::SpanParentResult { parent_span: None })
|
||||
}
|
||||
};
|
||||
match self.0.expand(
|
||||
subtree.view(),
|
||||
|
||||
@@ -22,6 +22,7 @@ pub enum SubRequest {
|
||||
LineColumn { file_id: u32, ast_id: u32, offset: u32 },
|
||||
ByteRange { file_id: u32, ast_id: u32, start: u32, end: u32 },
|
||||
SpanSource { file_id: u32, ast_id: u32, start: u32, end: u32, ctx: u32 },
|
||||
SpanParent { file_id: u32, ast_id: u32, start: u32, end: u32, ctx: u32 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -50,11 +51,23 @@ pub enum SubResponse {
|
||||
end: u32,
|
||||
ctx: u32,
|
||||
},
|
||||
SpanParentResult {
|
||||
parent_span: Option<ParentSpan>,
|
||||
},
|
||||
Cancel {
|
||||
reason: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ParentSpan {
|
||||
pub file_id: u32,
|
||||
pub ast_id: u32,
|
||||
pub start: u32,
|
||||
pub end: u32,
|
||||
pub ctx: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum BidirectionalMessage {
|
||||
Request(Request),
|
||||
|
||||
@@ -309,6 +309,40 @@ fn span_source(
|
||||
other => handle_failure(other),
|
||||
}
|
||||
}
|
||||
|
||||
fn span_parent(
|
||||
&mut self,
|
||||
proc_macro_srv::span::Span { range, anchor, ctx }: proc_macro_srv::span::Span,
|
||||
) -> Option<proc_macro_srv::span::Span> {
|
||||
let response = self.roundtrip(bidirectional::SubRequest::SpanParent {
|
||||
file_id: anchor.file_id.as_u32(),
|
||||
ast_id: anchor.ast_id.into_raw(),
|
||||
start: range.start().into(),
|
||||
end: range.end().into(),
|
||||
ctx: ctx.into_u32(),
|
||||
});
|
||||
|
||||
match response {
|
||||
Ok(bidirectional::SubResponse::SpanParentResult { parent_span }) => {
|
||||
parent_span.map(|bidirectional::ParentSpan { file_id, ast_id, start, end, ctx }| {
|
||||
proc_macro_srv::span::Span {
|
||||
range: proc_macro_srv::span::TextRange::new(
|
||||
proc_macro_srv::span::TextSize::new(start),
|
||||
proc_macro_srv::span::TextSize::new(end),
|
||||
),
|
||||
anchor: proc_macro_srv::span::SpanAnchor {
|
||||
file_id: proc_macro_srv::span::EditionedFileId::from_raw(file_id),
|
||||
ast_id: proc_macro_srv::span::ErasedFileAstId::from_raw(ast_id),
|
||||
},
|
||||
// SAFETY: spans originate from the server. If the protocol is violated,
|
||||
// undefined behavior is the caller’s responsibility.
|
||||
ctx: unsafe { proc_macro_srv::span::SyntaxContext::from_u32(ctx) },
|
||||
}
|
||||
})
|
||||
}
|
||||
other => handle_failure(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_expand_ra(
|
||||
|
||||
@@ -121,6 +121,7 @@ pub trait ProcMacroClientInterface {
|
||||
|
||||
fn byte_range(&mut self, span: Span) -> Range<usize>;
|
||||
fn span_source(&mut self, span: Span) -> Span;
|
||||
fn span_parent(&mut self, span: Span) -> Option<Span>;
|
||||
}
|
||||
|
||||
const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
@@ -164,8 +164,10 @@ fn span_source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||
self.callback.as_mut()?.source_text(span)
|
||||
}
|
||||
|
||||
fn span_parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
|
||||
// FIXME requires db, looks up the parent call site
|
||||
fn span_parent(&mut self, span: Self::Span) -> Option<Self::Span> {
|
||||
if let Some(ref mut callback) = self.callback {
|
||||
return callback.span_parent(span);
|
||||
}
|
||||
None
|
||||
}
|
||||
fn span_source(&mut self, span: Self::Span) -> Self::Span {
|
||||
|
||||
@@ -146,6 +146,10 @@ fn byte_range(&mut self, span: Span) -> Range<usize> {
|
||||
fn span_source(&mut self, span: Span) -> Span {
|
||||
span
|
||||
}
|
||||
|
||||
fn span_parent(&mut self, _span: Span) -> Option<Span> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_expand_with_callback(
|
||||
|
||||
@@ -158,14 +158,15 @@ pub(crate) fn make_lockfile_copy(
|
||||
build: semver::BuildMetadata::EMPTY,
|
||||
};
|
||||
|
||||
const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV: semver::Version =
|
||||
semver::Version {
|
||||
major: 1,
|
||||
minor: 95,
|
||||
patch: 0,
|
||||
pre: semver::Prerelease::EMPTY,
|
||||
build: semver::BuildMetadata::EMPTY,
|
||||
};
|
||||
// TODO: turn this into a const and remove pre once 1.95 is stable
|
||||
#[allow(non_snake_case)]
|
||||
let MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV: semver::Version = semver::Version {
|
||||
major: 1,
|
||||
minor: 95,
|
||||
patch: 0,
|
||||
pre: semver::Prerelease::new("nightly").unwrap(),
|
||||
build: semver::BuildMetadata::EMPTY,
|
||||
};
|
||||
|
||||
let usage = if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV {
|
||||
LockfileUsage::WithEnvVar
|
||||
|
||||
@@ -414,7 +414,8 @@ pub(crate) fn on_sync_mut<N>(
|
||||
let params = match not.extract::<N::Params>(N::METHOD) {
|
||||
Ok(it) => it,
|
||||
Err(ExtractError::JsonError { method, error }) => {
|
||||
panic!("Invalid request\nMethod: {method}\n error: {error}",)
|
||||
tracing::error!(method = %method, error = %error, "invalid notification");
|
||||
return self;
|
||||
}
|
||||
Err(ExtractError::MethodMismatch(not)) => {
|
||||
self.not = Some(not);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user