Merge from rustc
This commit is contained in:
commit
eb3ccfd841
338 changed files with 9244 additions and 3352 deletions
|
|
@ -122,6 +122,7 @@ static TARGETS: &[&str] = &[
|
|||
"riscv32imac-unknown-none-elf",
|
||||
"riscv32gc-unknown-linux-gnu",
|
||||
"riscv64imac-unknown-none-elf",
|
||||
"riscv64gc-unknown-hermit",
|
||||
"riscv64gc-unknown-none-elf",
|
||||
"riscv64gc-unknown-linux-gnu",
|
||||
"s390x-unknown-linux-gnu",
|
||||
|
|
@ -147,6 +148,7 @@ static TARGETS: &[&str] = &[
|
|||
"x86_64-pc-windows-msvc",
|
||||
"x86_64-sun-solaris",
|
||||
"x86_64-pc-solaris",
|
||||
"x86_64-unikraft-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-illumos",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
|
|
|
|||
|
|
@ -36,25 +36,26 @@ impl CiEnv {
|
|||
}
|
||||
|
||||
pub mod gha {
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Mutex;
|
||||
|
||||
static GROUP_ACTIVE: AtomicBool = AtomicBool::new(false);
|
||||
static ACTIVE_GROUPS: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
|
||||
/// All github actions log messages from this call to the Drop of the return value
|
||||
/// will be grouped and hidden by default in logs. Note that nesting these does
|
||||
/// not really work.
|
||||
/// will be grouped and hidden by default in logs. Note that since github actions doesn't
|
||||
/// support group nesting, any active group will be first finished when a subgroup is started,
|
||||
/// and then re-started when the subgroup finishes.
|
||||
#[track_caller]
|
||||
pub fn group(name: impl std::fmt::Display) -> Group {
|
||||
if std::env::var_os("GITHUB_ACTIONS").is_some() {
|
||||
eprintln!("::group::{name}");
|
||||
} else {
|
||||
eprintln!("{name}")
|
||||
let mut groups = ACTIVE_GROUPS.lock().unwrap();
|
||||
|
||||
// A group is currently active. End it first to avoid nesting.
|
||||
if !groups.is_empty() {
|
||||
end_group();
|
||||
}
|
||||
// https://github.com/actions/toolkit/issues/1001
|
||||
assert!(
|
||||
!GROUP_ACTIVE.swap(true, Ordering::Relaxed),
|
||||
"nested groups are not supported by GHA!"
|
||||
);
|
||||
|
||||
let name = name.to_string();
|
||||
start_group(&name);
|
||||
groups.push(name);
|
||||
Group(())
|
||||
}
|
||||
|
||||
|
|
@ -64,13 +65,36 @@ pub mod gha {
|
|||
|
||||
impl Drop for Group {
|
||||
fn drop(&mut self) {
|
||||
if std::env::var_os("GITHUB_ACTIONS").is_some() {
|
||||
eprintln!("::endgroup::");
|
||||
end_group();
|
||||
|
||||
let mut groups = ACTIVE_GROUPS.lock().unwrap();
|
||||
// Remove the current group
|
||||
groups.pop();
|
||||
|
||||
// If there was some previous group, restart it
|
||||
if is_in_gha() {
|
||||
if let Some(name) = groups.last() {
|
||||
start_group(format!("{name} (continued)"));
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
GROUP_ACTIVE.swap(false, Ordering::Relaxed),
|
||||
"group dropped but no group active!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn start_group(name: impl std::fmt::Display) {
|
||||
if is_in_gha() {
|
||||
eprintln!("::group::{name}");
|
||||
} else {
|
||||
eprintln!("{name}")
|
||||
}
|
||||
}
|
||||
|
||||
fn end_group() {
|
||||
if is_in_gha() {
|
||||
eprintln!("::endgroup::");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_in_gha() -> bool {
|
||||
std::env::var_os("GITHUB_ACTIONS").is_some()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 1b15556767f4b78a64e868eedf4073c423f02b93
|
||||
Subproject commit 7ac9416d82cd4fc5e707c9ec3574d22dff6466e5
|
||||
|
|
@ -328,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
{
|
||||
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
|
||||
// `&[u8]`. This change would prevent matching with different sized slices.
|
||||
} else {
|
||||
} else if !callsite.starts_with("env!") {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_LIT_AS_BYTES,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_middle::mir::{
|
|||
Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
|
||||
Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ImplSource, ObligationCause};
|
||||
use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
|
||||
use rustc_semver::RustcVersion;
|
||||
|
|
@ -411,7 +411,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
|
|||
|
||||
if !matches!(
|
||||
impl_src,
|
||||
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
|
|||
*b = *b;
|
||||
s = s;
|
||||
s.a = s.a;
|
||||
s.b[10] = s.b[5 + 5];
|
||||
s.b[9] = s.b[5 + 4];
|
||||
s.c[0][1] = s.c[0][1];
|
||||
s.b[a] = s.b[a];
|
||||
*s.e = *s.e;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ error: self-assignment of `s.a` to `s.a`
|
|||
LL | s.a = s.a;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
|
||||
error: self-assignment of `s.b[5 + 4]` to `s.b[9]`
|
||||
--> $DIR/self_assignment.rs:17:5
|
||||
|
|
||||
LL | s.b[10] = s.b[5 + 5];
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
LL | s.b[9] = s.b[5 + 4];
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
|
||||
--> $DIR/self_assignment.rs:18:5
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::io::BufReader;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use tracing::*;
|
||||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
|
|
@ -298,13 +297,6 @@ impl TestProps {
|
|||
/// `//[foo]`), then the property is ignored unless `cfg` is
|
||||
/// `Some("foo")`.
|
||||
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
|
||||
// In CI, we've sometimes encountered non-determinism related to truncating very long paths.
|
||||
// Set a consistent (short) prefix to avoid issues, but only in CI to avoid regressing the
|
||||
// contributor experience.
|
||||
if CiEnv::is_ci() {
|
||||
self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
|
||||
}
|
||||
|
||||
let mut has_edition = false;
|
||||
if !testfile.is_dir() {
|
||||
let file = File::open(testfile).unwrap();
|
||||
|
|
|
|||
|
|
@ -2330,6 +2330,7 @@ impl<'test> TestCx<'test> {
|
|||
// Hide line numbers to reduce churn
|
||||
rustc.arg("-Zui-testing");
|
||||
rustc.arg("-Zdeduplicate-diagnostics=no");
|
||||
rustc.arg("-Zwrite-long-types-to-disk=no");
|
||||
// FIXME: use this for other modes too, for perf?
|
||||
rustc.arg("-Cstrip=debuginfo");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,13 +928,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
impl<'ecx, 'mir, 'tcx> ValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
for RetagVisitor<'ecx, 'mir, 'tcx>
|
||||
{
|
||||
type V = PlaceTy<'tcx, Provenance>;
|
||||
|
||||
#[inline(always)]
|
||||
fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
|
||||
fn ecx(&self) -> &MiriInterpCx<'mir, 'tcx> {
|
||||
self.ecx
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -413,13 +413,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
impl<'ecx, 'mir, 'tcx> ValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
for RetagVisitor<'ecx, 'mir, 'tcx>
|
||||
{
|
||||
type V = PlaceTy<'tcx, Provenance>;
|
||||
|
||||
#[inline(always)]
|
||||
fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
|
||||
fn ecx(&self) -> &MiriInterpCx<'mir, 'tcx> {
|
||||
self.ecx
|
||||
}
|
||||
|
||||
|
|
@ -578,14 +578,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
/// I.e. input is what you get from the visitor upon encountering an `adt` that is `Unique`,
|
||||
/// and output can be used by `retag_ptr_inplace`.
|
||||
fn inner_ptr_of_unique<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'_, 'tcx>,
|
||||
ecx: &MiriInterpCx<'_, 'tcx>,
|
||||
place: &PlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
// Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in
|
||||
// `rustc_const_eval`, just with one fewer layer.
|
||||
// Here we have a `Unique(NonNull(*mut), PhantomData)`
|
||||
assert_eq!(place.layout.fields.count(), 2, "Unique must have exactly 2 fields");
|
||||
let (nonnull, phantom) = (ecx.place_field(place, 0)?, ecx.place_field(place, 1)?);
|
||||
let (nonnull, phantom) = (ecx.project_field(place, 0)?, ecx.project_field(place, 1)?);
|
||||
assert!(
|
||||
phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
|
||||
"2nd field of `Unique` should be `PhantomData` but is `{:?}`",
|
||||
|
|
@ -593,7 +593,7 @@ fn inner_ptr_of_unique<'tcx>(
|
|||
);
|
||||
// Now down to `NonNull(*mut)`
|
||||
assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field");
|
||||
let ptr = ecx.place_field(&nonnull, 0)?;
|
||||
let ptr = ecx.project_field(&nonnull, 0)?;
|
||||
// Finally a plain `*mut`
|
||||
Ok(ptr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||
))?;
|
||||
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
|
||||
for (idx, arg) in argvs.into_iter().enumerate() {
|
||||
let place = ecx.mplace_field(&argvs_place, idx)?;
|
||||
let place = ecx.project_field(&argvs_place, idx)?;
|
||||
ecx.write_immediate(arg, &place.into())?;
|
||||
}
|
||||
ecx.mark_immutable(&argvs_place);
|
||||
|
|
@ -354,7 +354,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||
ecx.machine.cmd_line = Some(*cmd_place);
|
||||
// Store the UTF-16 string. We just allocated so we know the bounds are fine.
|
||||
for (idx, &c) in cmd_utf16.iter().enumerate() {
|
||||
let place = ecx.mplace_field(&cmd_place, idx)?;
|
||||
let place = ecx.project_field(&cmd_place, idx)?;
|
||||
ecx.write_scalar(Scalar::from_u16(c), &place.into())?;
|
||||
}
|
||||
ecx.mark_immutable(&cmd_place);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use log::trace;
|
|||
|
||||
use rustc_hir::def::{DefKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
|
|
@ -17,7 +18,7 @@ use rustc_middle::ty::{
|
|||
List, TyCtxt,
|
||||
};
|
||||
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
|
||||
use rustc_target::abi::{Align, FieldsShape, Size, Variants};
|
||||
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use rand::RngCore;
|
||||
|
|
@ -229,20 +230,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.layout_of(ty).unwrap()
|
||||
}
|
||||
|
||||
/// Project to the given *named* field of the mplace (which must be a struct or union type).
|
||||
fn mplace_field_named(
|
||||
/// Project to the given *named* field (which must be a struct or union type).
|
||||
fn project_field_named<P: Projectable<'mir, 'tcx, Provenance>>(
|
||||
&self,
|
||||
mplace: &MPlaceTy<'tcx, Provenance>,
|
||||
base: &P,
|
||||
name: &str,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
|
||||
) -> InterpResult<'tcx, P> {
|
||||
let this = self.eval_context_ref();
|
||||
let adt = mplace.layout.ty.ty_adt_def().unwrap();
|
||||
let adt = base.layout().ty.ty_adt_def().unwrap();
|
||||
for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
|
||||
if field.name.as_str() == name {
|
||||
return this.mplace_field(mplace, idx);
|
||||
return this.project_field(base, idx);
|
||||
}
|
||||
}
|
||||
bug!("No field named {} in type {}", name, mplace.layout.ty);
|
||||
bug!("No field named {} in type {}", name, base.layout().ty);
|
||||
}
|
||||
|
||||
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
|
||||
|
|
@ -270,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
for (idx, &val) in values.iter().enumerate() {
|
||||
let field = this.mplace_field(dest, idx)?;
|
||||
let field = this.project_field(dest, idx)?;
|
||||
this.write_int(val, &field.into())?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -284,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
for &(name, val) in values.iter() {
|
||||
let field = this.mplace_field_named(dest, name)?;
|
||||
let field = this.project_field_named(dest, name)?;
|
||||
this.write_int(val, &field.into())?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -301,8 +302,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
/// Get the `Place` for a local
|
||||
fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
fn local_place(&self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
let place = mir::Place { local, projection: List::empty() };
|
||||
this.eval_place(place)
|
||||
}
|
||||
|
|
@ -479,6 +480,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
self.ecx
|
||||
}
|
||||
|
||||
fn aggregate_field_order(memory_index: &IndexVec<FieldIdx, u32>, idx: usize) -> usize {
|
||||
// We need to do an *inverse* lookup: find the field that has position `idx` in memory order.
|
||||
for (src_field, &mem_pos) in memory_index.iter_enumerated() {
|
||||
if mem_pos as usize == idx {
|
||||
return src_field.as_usize();
|
||||
}
|
||||
}
|
||||
panic!("invalid `memory_index`, could not find {}-th field in memory order", idx);
|
||||
}
|
||||
|
||||
// Hook to detect `UnsafeCell`.
|
||||
fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
|
||||
|
|
@ -524,33 +535,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we visit aggregates in increasing offset order.
|
||||
fn visit_aggregate(
|
||||
&mut self,
|
||||
place: &MPlaceTy<'tcx, Provenance>,
|
||||
fields: impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Provenance>>>,
|
||||
) -> InterpResult<'tcx> {
|
||||
match place.layout.fields {
|
||||
FieldsShape::Array { .. } => {
|
||||
// For the array layout, we know the iterator will yield sorted elements so
|
||||
// we can avoid the allocation.
|
||||
self.walk_aggregate(place, fields)
|
||||
}
|
||||
FieldsShape::Arbitrary { .. } => {
|
||||
// Gather the subplaces and sort them before visiting.
|
||||
let mut places = fields
|
||||
.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Provenance>>>>()?;
|
||||
// we just compare offsets, the abs. value never matters
|
||||
places.sort_by_key(|place| place.ptr.addr());
|
||||
self.walk_aggregate(place, places.into_iter().map(Ok))
|
||||
}
|
||||
FieldsShape::Union { .. } | FieldsShape::Primitive => {
|
||||
// Uh, what?
|
||||
bug!("unions/primitives are not aggregates we should ever visit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_union(
|
||||
&mut self,
|
||||
_v: &MPlaceTy<'tcx, Provenance>,
|
||||
|
|
@ -746,7 +730,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(mplace)
|
||||
}
|
||||
|
||||
fn deref_pointer_as(
|
||||
/// Deref' a pointer *without* checking that the place is dereferenceable.
|
||||
fn deref_pointer_unchecked(
|
||||
&self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
|
|
@ -811,10 +796,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
tp: &MPlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Option<Duration>> {
|
||||
let this = self.eval_context_mut();
|
||||
let seconds_place = this.mplace_field(tp, 0)?;
|
||||
let seconds_place = this.project_field(tp, 0)?;
|
||||
let seconds_scalar = this.read_scalar(&seconds_place.into())?;
|
||||
let seconds = seconds_scalar.to_target_isize(this)?;
|
||||
let nanoseconds_place = this.mplace_field(tp, 1)?;
|
||||
let nanoseconds_place = this.project_field(tp, 1)?;
|
||||
let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?;
|
||||
let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
// Write pointers into array
|
||||
for (i, ptr) in ptrs.into_iter().enumerate() {
|
||||
let place = this.mplace_index(&alloc, i as u64)?;
|
||||
let place = this.project_index(&alloc, i as u64)?;
|
||||
|
||||
this.write_pointer(ptr, &place.into())?;
|
||||
}
|
||||
|
|
@ -196,33 +196,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
this.write_immediate(
|
||||
name_alloc.to_ref(this),
|
||||
&this.mplace_field(&dest, 0)?.into(),
|
||||
&this.project_field(&dest, 0)?.into(),
|
||||
)?;
|
||||
this.write_immediate(
|
||||
filename_alloc.to_ref(this),
|
||||
&this.mplace_field(&dest, 1)?.into(),
|
||||
&this.project_field(&dest, 1)?.into(),
|
||||
)?;
|
||||
}
|
||||
1 => {
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(name.len().try_into().unwrap(), this),
|
||||
&this.mplace_field(&dest, 0)?.into(),
|
||||
&this.project_field(&dest, 0)?.into(),
|
||||
)?;
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(filename.len().try_into().unwrap(), this),
|
||||
&this.mplace_field(&dest, 1)?.into(),
|
||||
&this.project_field(&dest, 1)?.into(),
|
||||
)?;
|
||||
}
|
||||
_ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags),
|
||||
}
|
||||
|
||||
this.write_scalar(Scalar::from_u32(lineno), &this.mplace_field(&dest, 2)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(colno), &this.mplace_field(&dest, 3)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(lineno), &this.project_field(&dest, 2)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(colno), &this.project_field(&dest, 3)?.into())?;
|
||||
|
||||
// Support a 4-field struct for now - this is deprecated
|
||||
// and slated for removal.
|
||||
if num_fields == 5 {
|
||||
this.write_pointer(fn_ptr, &this.mplace_field(&dest, 4)?.into())?;
|
||||
this.write_pointer(fn_ptr, &this.project_field(&dest, 4)?.into())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
))?;
|
||||
let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
|
||||
for (idx, var) in vars.into_iter().enumerate() {
|
||||
let place = this.mplace_field(&vars_place, idx)?;
|
||||
let place = this.project_field(&vars_place, idx)?;
|
||||
this.write_pointer(var, &place.into())?;
|
||||
}
|
||||
this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?;
|
||||
|
|
|
|||
|
|
@ -942,9 +942,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
#[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64
|
||||
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
|
||||
|
||||
let c_out_field = this.place_field(dest, 0)?;
|
||||
let c_out_field = this.project_field(dest, 0)?;
|
||||
this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?;
|
||||
let sum_field = this.place_field(dest, 1)?;
|
||||
let sum_field = this.project_field(dest, 1)?;
|
||||
this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
|
||||
}
|
||||
"llvm.x86.sse2.pause"
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
for i in 0..dest_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
let val = match which {
|
||||
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
|
||||
Op::Abs => {
|
||||
|
|
@ -172,9 +172,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
for i in 0..dest_len {
|
||||
let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?;
|
||||
let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let left = this.read_immediate(&this.project_index(&left, i)?.into())?;
|
||||
let right = this.read_immediate(&this.project_index(&right, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
let val = match which {
|
||||
Op::MirOp(mir_op) => {
|
||||
let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?;
|
||||
|
|
@ -232,10 +232,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, c_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let a = this.read_scalar(&this.mplace_index(&a, i)?.into())?;
|
||||
let b = this.read_scalar(&this.mplace_index(&b, i)?.into())?;
|
||||
let c = this.read_scalar(&this.mplace_index(&c, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let a = this.read_scalar(&this.project_index(&a, i)?.into())?;
|
||||
let b = this.read_scalar(&this.project_index(&b, i)?.into())?;
|
||||
let c = this.read_scalar(&this.project_index(&c, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
// Works for f32 and f64.
|
||||
// FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
|
||||
|
|
@ -295,13 +295,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
// Initialize with first lane, then proceed with the rest.
|
||||
let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?;
|
||||
let mut res = this.read_immediate(&this.project_index(&op, 0)?.into())?;
|
||||
if matches!(which, Op::MirOpBool(_)) {
|
||||
// Convert to `bool` scalar.
|
||||
res = imm_from_bool(simd_element_to_bool(res)?);
|
||||
}
|
||||
for i in 1..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
res = match which {
|
||||
Op::MirOp(mir_op) => {
|
||||
this.binary_op(mir_op, &res, &op)?
|
||||
|
|
@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let mut res = init;
|
||||
for i in 0..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
res = this.binary_op(mir_op, &res, &op)?;
|
||||
}
|
||||
this.write_immediate(*res, dest)?;
|
||||
|
|
@ -372,10 +372,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, no_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?;
|
||||
let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
let yes = this.read_immediate(&this.project_index(&yes, i)?.into())?;
|
||||
let no = this.read_immediate(&this.project_index(&no, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if simd_element_to_bool(mask)? { yes } else { no };
|
||||
this.write_immediate(*val, &dest.into())?;
|
||||
|
|
@ -403,9 +403,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
& 1u64
|
||||
.checked_shl(simd_bitmask_index(i, dest_len, this.data_layout().endian))
|
||||
.unwrap();
|
||||
let yes = this.read_immediate(&this.mplace_index(&yes, i.into())?.into())?;
|
||||
let no = this.read_immediate(&this.mplace_index(&no, i.into())?.into())?;
|
||||
let dest = this.mplace_index(&dest, i.into())?;
|
||||
let yes = this.read_immediate(&this.project_index(&yes, i.into())?.into())?;
|
||||
let no = this.read_immediate(&this.project_index(&no, i.into())?.into())?;
|
||||
let dest = this.project_index(&dest, i.into())?;
|
||||
|
||||
let val = if mask != 0 { yes } else { no };
|
||||
this.write_immediate(*val, &dest.into())?;
|
||||
|
|
@ -435,8 +435,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let from_exposed_cast = intrinsic_name == "from_exposed_addr";
|
||||
|
||||
for i in 0..dest_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
|
||||
// Int-to-(int|float): always safe
|
||||
|
|
@ -496,17 +496,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
for i in 0..dest_len {
|
||||
let src_index: u64 = this
|
||||
.read_immediate(&this.operand_index(index, i)?)?
|
||||
.read_immediate(&this.project_index(index, i)?)?
|
||||
.to_scalar()
|
||||
.to_u32()?
|
||||
.into();
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if src_index < left_len {
|
||||
this.read_immediate(&this.mplace_index(&left, src_index)?.into())?
|
||||
this.read_immediate(&this.project_index(&left, src_index)?.into())?
|
||||
} else if src_index < left_len.checked_add(right_len).unwrap() {
|
||||
let right_idx = src_index.checked_sub(left_len).unwrap();
|
||||
this.read_immediate(&this.mplace_index(&right, right_idx)?.into())?
|
||||
this.read_immediate(&this.project_index(&right, right_idx)?.into())?
|
||||
} else {
|
||||
span_bug!(
|
||||
this.cur_span(),
|
||||
|
|
@ -528,10 +528,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, mask_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let passthru = this.read_immediate(&this.project_index(&passthru, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr.into())?;
|
||||
|
|
@ -552,9 +552,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(ptrs_len, mask_len);
|
||||
|
||||
for i in 0..ptrs_len {
|
||||
let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let value = this.read_immediate(&this.project_index(&value, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
|
||||
if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr.into())?;
|
||||
|
|
@ -578,7 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let mut res = 0u64;
|
||||
for i in 0..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i.into())?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i.into())?.into())?;
|
||||
if simd_element_to_bool(op)? {
|
||||
res |= 1u64
|
||||
.checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian))
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
#[allow(deprecated)]
|
||||
let home_dir = std::env::home_dir().unwrap();
|
||||
let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
|
||||
let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
|
||||
let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
|
||||
this.write_pointer(buf, &pw_dir.into())?;
|
||||
|
||||
if written {
|
||||
|
|
|
|||
|
|
@ -1141,7 +1141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", access_sec.into()),
|
||||
("tv_nsec", access_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_atime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_atime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1149,7 +1149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", created_sec.into()),
|
||||
("tv_nsec", created_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_btime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_btime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1157,7 +1157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", 0.into()),
|
||||
("tv_nsec", 0.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_ctime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_ctime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1165,7 +1165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", modified_sec.into()),
|
||||
("tv_nsec", modified_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_mtime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_mtime")?,
|
||||
)?;
|
||||
|
||||
Ok(0)
|
||||
|
|
@ -1421,7 +1421,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// }
|
||||
|
||||
let entry_place = this.deref_operand_as(entry_op, this.libc_ty_layout("dirent"))?;
|
||||
let name_place = this.mplace_field(&entry_place, 5)?;
|
||||
let name_place = this.project_field(&entry_place, 5)?;
|
||||
|
||||
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
||||
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if op == epoll_ctl_add || op == epoll_ctl_mod {
|
||||
let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?;
|
||||
|
||||
let events = this.mplace_field(&event, 0)?;
|
||||
let events = this.project_field(&event, 0)?;
|
||||
let events = this.read_scalar(&events.into())?.to_u32()?;
|
||||
let data = this.mplace_field(&event, 1)?;
|
||||
let data = this.project_field(&event, 1)?;
|
||||
let data = this.read_scalar(&data.into())?;
|
||||
let event = EpollEvent { events, data };
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ pub fn futex<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let timeout = this.deref_pointer_as(
|
||||
// `read_timespec` will check the place when it is not null.
|
||||
let timeout = this.deref_pointer_unchecked(
|
||||
&this.read_immediate(&args[3])?,
|
||||
this.libc_ty_layout("timespec"),
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// We have to put the result into io_status_block.
|
||||
if let Some(n) = written {
|
||||
let io_status_information =
|
||||
this.mplace_field_named(&io_status_block, "Information")?;
|
||||
this.project_field_named(&io_status_block, "Information")?;
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(n.into(), this),
|
||||
&io_status_information.into(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! Tests for various intrinsics that do not fit anywhere else.
|
||||
|
||||
use std::intrinsics;
|
||||
use std::mem::{size_of, size_of_val, size_of_val_raw};
|
||||
use std::mem::{size_of, size_of_val, size_of_val_raw, discriminant};
|
||||
|
||||
struct Bomb;
|
||||
|
||||
|
|
@ -39,4 +39,7 @@ fn main() {
|
|||
let _v = intrinsics::discriminant_value(&0);
|
||||
let _v = intrinsics::discriminant_value(&true);
|
||||
let _v = intrinsics::discriminant_value(&vec![1, 2, 3]);
|
||||
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
|
||||
// only the discriminant, nothing about the data.
|
||||
assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,10 +161,21 @@ jobs:
|
|||
# if: runner.os == 'Linux'
|
||||
# working-directory: ./editors/code
|
||||
|
||||
# If this steps fails, your code's type integrity might be wrong at some places at TypeScript level.
|
||||
- run: npm run typecheck
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
# You may fix the code automatically by running `npm run lint:fix` if this steps fails.
|
||||
- run: npm run lint
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
# To fix this steps, please run `npm run format`.
|
||||
- run: npm run format:check
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
- name: Run VS Code tests (Linux)
|
||||
if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true'
|
||||
env:
|
||||
|
|
@ -179,10 +190,6 @@ jobs:
|
|||
run: npm test
|
||||
working-directory: ./editors/code
|
||||
|
||||
- run: npm run pretest
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
- run: npm run package --scripts-prepend-node-path
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
|
|
|||
|
|
@ -634,7 +634,7 @@ impl Printer<'_> {
|
|||
match literal {
|
||||
Literal::String(it) => w!(self, "{:?}", it),
|
||||
Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
|
||||
Literal::CString(it) => w!(self, "\"{}\\0\"", it),
|
||||
Literal::CString(it) => w!(self, "\"{}\\0\"", it.escape_ascii()),
|
||||
Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
|
||||
Literal::Bool(it) => w!(self, "{}", it),
|
||||
Literal::Int(i, suffix) => {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl fmt::Display for FloatTypeWrapper {
|
|||
pub enum Literal {
|
||||
String(Box<str>),
|
||||
ByteString(Box<[u8]>),
|
||||
CString(Box<str>),
|
||||
CString(Box<[u8]>),
|
||||
Char(char),
|
||||
Bool(bool),
|
||||
Int(i128, Option<BuiltinInt>),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ use triomphe::Arc;
|
|||
use crate::{
|
||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
|
||||
mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
|
||||
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder,
|
||||
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
|
||||
TyBuilder,
|
||||
};
|
||||
|
||||
use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
|
||||
|
|
@ -135,7 +136,7 @@ pub fn intern_const_ref(
|
|||
ty: Ty,
|
||||
krate: CrateId,
|
||||
) -> Const {
|
||||
let layout = db.layout_of_ty(ty.clone(), krate);
|
||||
let layout = db.layout_of_ty(ty.clone(), Arc::new(TraitEnvironment::empty(krate)));
|
||||
let bytes = match value {
|
||||
LiteralConstRef::Int(i) => {
|
||||
// FIXME: We should handle failure of layout better.
|
||||
|
|
@ -173,7 +174,7 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
|
|||
chalk_ir::ConstValue::Concrete(c) => match &c.interned {
|
||||
ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(&it, false))),
|
||||
ConstScalar::UnevaluatedConst(c, subst) => {
|
||||
let ec = db.const_eval(*c, subst.clone()).ok()?;
|
||||
let ec = db.const_eval(*c, subst.clone(), None).ok()?;
|
||||
try_const_usize(db, &ec)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -186,6 +187,7 @@ pub(crate) fn const_eval_recover(
|
|||
_: &[String],
|
||||
_: &GeneralConstId,
|
||||
_: &Substitution,
|
||||
_: &Option<Arc<TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError> {
|
||||
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
|
||||
}
|
||||
|
|
@ -210,6 +212,7 @@ pub(crate) fn const_eval_query(
|
|||
db: &dyn HirDatabase,
|
||||
def: GeneralConstId,
|
||||
subst: Substitution,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError> {
|
||||
let body = match def {
|
||||
GeneralConstId::ConstId(c) => {
|
||||
|
|
@ -228,7 +231,7 @@ pub(crate) fn const_eval_query(
|
|||
}
|
||||
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
|
||||
};
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
let c = interpret_mir(db, body, false, trait_env).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +244,7 @@ pub(crate) fn const_eval_static_query(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def.into()),
|
||||
)?;
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
let c = interpret_mir(db, body, false, None).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +271,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def),
|
||||
)?;
|
||||
let c = interpret_mir(db, mir_body, false).0?;
|
||||
let c = interpret_mir(db, mir_body, false, None).0?;
|
||||
let c = try_const_usize(db, &c).unwrap() as i128;
|
||||
Ok(c)
|
||||
}
|
||||
|
|
@ -293,7 +296,7 @@ pub(crate) fn eval_to_const(
|
|||
}
|
||||
let infer = ctx.clone().resolve_all();
|
||||
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
|
||||
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
|
||||
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true, None).0 {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ fn eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError> {
|
|||
_ => None,
|
||||
})
|
||||
.expect("No const named GOAL found in the test");
|
||||
db.const_eval(const_id.into(), Substitution::empty(Interner))
|
||||
db.const_eval(const_id.into(), Substitution::empty(Interner), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1941,6 +1941,33 @@ fn dyn_trait() {
|
|||
"#,
|
||||
900,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: coerce_unsized, index, slice
|
||||
trait A {
|
||||
fn x(&self) -> i32;
|
||||
}
|
||||
|
||||
trait B: A {}
|
||||
|
||||
impl A for i32 {
|
||||
fn x(&self) -> i32 {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl B for i32 {
|
||||
|
||||
}
|
||||
|
||||
const fn f(x: &dyn B) -> i32 {
|
||||
x.x()
|
||||
}
|
||||
|
||||
const GOAL: i32 = f(&2i32);
|
||||
"#,
|
||||
5,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2492,6 +2519,28 @@ fn const_trait_assoc() {
|
|||
"#,
|
||||
5,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: size_of
|
||||
//- /a/lib.rs crate:a
|
||||
use core::mem::size_of;
|
||||
pub struct S<T>(T);
|
||||
impl<T> S<T> {
|
||||
pub const X: usize = core::mem::size_of::<T>();
|
||||
}
|
||||
//- /main.rs crate:main deps:a
|
||||
use a::{S};
|
||||
trait Tr {
|
||||
type Ty;
|
||||
}
|
||||
impl Tr for i32 {
|
||||
type Ty = u64;
|
||||
}
|
||||
struct K<T: Tr>(<T as Tr>::Ty);
|
||||
const GOAL: usize = S::<K<i32>>::X;
|
||||
"#,
|
||||
8,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
struct S<T>(*mut T);
|
||||
|
|
|
|||
|
|
@ -77,8 +77,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(&self, def: GeneralConstId, subst: Substitution)
|
||||
-> Result<Const, ConstEvalError>;
|
||||
fn const_eval(
|
||||
&self,
|
||||
def: GeneralConstId,
|
||||
subst: Substitution,
|
||||
trait_env: Option<Arc<crate::TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_static_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_static_recover)]
|
||||
|
|
@ -100,12 +104,16 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
&self,
|
||||
def: AdtId,
|
||||
subst: Substitution,
|
||||
krate: CrateId,
|
||||
env: Arc<crate::TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError>;
|
||||
|
||||
#[salsa::invoke(crate::layout::layout_of_ty_query)]
|
||||
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
|
||||
fn layout_of_ty(&self, ty: Ty, krate: CrateId) -> Result<Arc<Layout>, LayoutError>;
|
||||
fn layout_of_ty(
|
||||
&self,
|
||||
ty: Ty,
|
||||
env: Arc<crate::TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError>;
|
||||
|
||||
#[salsa::invoke(crate::layout::target_data_layout_query)]
|
||||
fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
|
||||
|
|
|
|||
|
|
@ -14,13 +14,12 @@ mod case_conv;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
hir::{Pat, PatId},
|
||||
src::HasSource,
|
||||
AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId,
|
||||
StructId,
|
||||
AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId,
|
||||
Lookup, ModuleDefId, StaticId, StructId,
|
||||
};
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
|
|
@ -44,13 +43,9 @@ mod allow {
|
|||
pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
|
||||
}
|
||||
|
||||
pub fn incorrect_case(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
owner: ModuleDefId,
|
||||
) -> Vec<IncorrectCase> {
|
||||
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
|
||||
let _p = profile::span("validate_module_item");
|
||||
let mut validator = DeclValidator::new(db, krate);
|
||||
let mut validator = DeclValidator::new(db);
|
||||
validator.validate_item(owner);
|
||||
validator.sink
|
||||
}
|
||||
|
|
@ -120,7 +115,6 @@ pub struct IncorrectCase {
|
|||
|
||||
pub(super) struct DeclValidator<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
pub(super) sink: Vec<IncorrectCase>,
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +126,8 @@ struct Replacement {
|
|||
}
|
||||
|
||||
impl<'a> DeclValidator<'a> {
|
||||
pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
|
||||
DeclValidator { db, krate, sink: Vec::new() }
|
||||
pub(super) fn new(db: &'a dyn HirDatabase) -> DeclValidator<'a> {
|
||||
DeclValidator { db, sink: Vec::new() }
|
||||
}
|
||||
|
||||
pub(super) fn validate_item(&mut self, item: ModuleDefId) {
|
||||
|
|
@ -195,8 +189,7 @@ impl<'a> DeclValidator<'a> {
|
|||
AttrDefId::TypeAliasId(_) => None,
|
||||
AttrDefId::GenericParamId(_) => None,
|
||||
}
|
||||
.map(|mid| self.allowed(mid, allow_name, true))
|
||||
.unwrap_or(false)
|
||||
.is_some_and(|mid| self.allowed(mid, allow_name, true))
|
||||
}
|
||||
|
||||
fn validate_func(&mut self, func: FunctionId) {
|
||||
|
|
@ -206,17 +199,7 @@ impl<'a> DeclValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let body = self.db.body(func.into());
|
||||
|
||||
// Recursively validate inner scope items, such as static variables and constants.
|
||||
for (_, block_def_map) in body.blocks(self.db.upcast()) {
|
||||
for (_, module) in block_def_map.modules() {
|
||||
for def_id in module.scope.declarations() {
|
||||
let mut validator = DeclValidator::new(self.db, self.krate);
|
||||
validator.validate_item(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.validate_body_inner_items(func.into());
|
||||
|
||||
// Check whether non-snake case identifiers are allowed for this function.
|
||||
if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
|
||||
|
|
@ -231,6 +214,8 @@ impl<'a> DeclValidator<'a> {
|
|||
expected_case: CaseType::LowerSnakeCase,
|
||||
});
|
||||
|
||||
let body = self.db.body(func.into());
|
||||
|
||||
// Check the patterns inside the function body.
|
||||
// This includes function parameters.
|
||||
let pats_replacements = body
|
||||
|
|
@ -496,6 +481,11 @@ impl<'a> DeclValidator<'a> {
|
|||
fn validate_enum(&mut self, enum_id: EnumId) {
|
||||
let data = self.db.enum_data(enum_id);
|
||||
|
||||
for (local_id, _) in data.variants.iter() {
|
||||
let variant_id = EnumVariantId { parent: enum_id, local_id };
|
||||
self.validate_body_inner_items(variant_id.into());
|
||||
}
|
||||
|
||||
// Check whether non-camel case names are allowed for this enum.
|
||||
if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
|
||||
return;
|
||||
|
|
@ -512,13 +502,11 @@ impl<'a> DeclValidator<'a> {
|
|||
// Check the field names.
|
||||
let enum_fields_replacements = data
|
||||
.variants
|
||||
.iter()
|
||||
.filter_map(|(_, variant)| {
|
||||
.values()
|
||||
.filter_map(|variant| {
|
||||
Some(Replacement {
|
||||
current_name: variant.name.clone(),
|
||||
suggested_text: to_camel_case(
|
||||
&variant.name.display(self.db.upcast()).to_string(),
|
||||
)?,
|
||||
suggested_text: to_camel_case(&variant.name.to_smol_str())?,
|
||||
expected_case: CaseType::UpperCamelCase,
|
||||
})
|
||||
})
|
||||
|
|
@ -622,6 +610,8 @@ impl<'a> DeclValidator<'a> {
|
|||
fn validate_const(&mut self, const_id: ConstId) {
|
||||
let data = self.db.const_data(const_id);
|
||||
|
||||
self.validate_body_inner_items(const_id.into());
|
||||
|
||||
if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -631,7 +621,7 @@ impl<'a> DeclValidator<'a> {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let const_name = name.display(self.db.upcast()).to_string();
|
||||
let const_name = name.to_smol_str();
|
||||
let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) {
|
||||
Replacement {
|
||||
current_name: name.clone(),
|
||||
|
|
@ -670,13 +660,15 @@ impl<'a> DeclValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.validate_body_inner_items(static_id.into());
|
||||
|
||||
if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = &data.name;
|
||||
|
||||
let static_name = name.display(self.db.upcast()).to_string();
|
||||
let static_name = name.to_smol_str();
|
||||
let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) {
|
||||
Replacement {
|
||||
current_name: name.clone(),
|
||||
|
|
@ -707,4 +699,17 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
self.sink.push(diagnostic);
|
||||
}
|
||||
|
||||
// FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`.
|
||||
/// Recursively validates inner scope items, such as static variables and constants.
|
||||
fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) {
|
||||
let body = self.db.body(body_id);
|
||||
for (_, block_def_map) in body.blocks(self.db.upcast()) {
|
||||
for (_, module) in block_def_map.modules() {
|
||||
for def_id in module.scope.declarations() {
|
||||
self.validate_item(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use itertools::Itertools;
|
|||
use la_arena::ArenaMap;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
consteval::try_const_usize,
|
||||
|
|
@ -43,7 +44,7 @@ use crate::{
|
|||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
|
||||
DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
|
||||
MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
|
||||
Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
|
||||
Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
|
||||
};
|
||||
|
||||
pub trait HirWrite: fmt::Write {
|
||||
|
|
@ -454,7 +455,9 @@ fn render_const_scalar(
|
|||
) -> Result<(), HirDisplayError> {
|
||||
// FIXME: We need to get krate from the final callers of the hir display
|
||||
// infrastructure and have it here as a field on `f`.
|
||||
let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
|
||||
let trait_env = Arc::new(TraitEnvironment::empty(
|
||||
*f.db.crate_graph().crates_in_topological_order().last().unwrap(),
|
||||
));
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Scalar(s) => match s {
|
||||
Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
|
||||
|
|
@ -497,7 +500,7 @@ fn render_const_scalar(
|
|||
TyKind::Slice(ty) => {
|
||||
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
|
||||
let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size_one = layout.size.bytes_usize();
|
||||
|
|
@ -523,7 +526,7 @@ fn render_const_scalar(
|
|||
let Ok(t) = memory_map.vtable.ty(ty_id) else {
|
||||
return f.write_str("<ty-missing-in-vtable-map>");
|
||||
};
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
@ -555,7 +558,7 @@ fn render_const_scalar(
|
|||
return f.write_str("<layout-error>");
|
||||
}
|
||||
});
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
@ -567,7 +570,7 @@ fn render_const_scalar(
|
|||
}
|
||||
},
|
||||
TyKind::Tuple(_, subst) => {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
f.write_str("(")?;
|
||||
|
|
@ -580,7 +583,7 @@ fn render_const_scalar(
|
|||
}
|
||||
let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
|
||||
let offset = layout.fields.offset(id).bytes_usize();
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
f.write_str("<layout-error>")?;
|
||||
continue;
|
||||
};
|
||||
|
|
@ -590,7 +593,7 @@ fn render_const_scalar(
|
|||
f.write_str(")")
|
||||
}
|
||||
TyKind::Adt(adt, subst) => {
|
||||
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
match adt.0 {
|
||||
|
|
@ -602,7 +605,7 @@ fn render_const_scalar(
|
|||
&data.variant_data,
|
||||
f,
|
||||
&field_types,
|
||||
adt.0.module(f.db.upcast()).krate(),
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
&layout,
|
||||
subst,
|
||||
b,
|
||||
|
|
@ -614,7 +617,7 @@ fn render_const_scalar(
|
|||
}
|
||||
hir_def::AdtId::EnumId(e) => {
|
||||
let Some((var_id, var_layout)) =
|
||||
detect_variant_from_bytes(&layout, f.db, krate, b, e)
|
||||
detect_variant_from_bytes(&layout, f.db, trait_env.clone(), b, e)
|
||||
else {
|
||||
return f.write_str("<failed-to-detect-variant>");
|
||||
};
|
||||
|
|
@ -626,7 +629,7 @@ fn render_const_scalar(
|
|||
&data.variant_data,
|
||||
f,
|
||||
&field_types,
|
||||
adt.0.module(f.db.upcast()).krate(),
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
&var_layout,
|
||||
subst,
|
||||
b,
|
||||
|
|
@ -645,7 +648,7 @@ fn render_const_scalar(
|
|||
let Some(len) = try_const_usize(f.db, len) else {
|
||||
return f.write_str("<unknown-array-len>");
|
||||
};
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size_one = layout.size.bytes_usize();
|
||||
|
|
@ -684,7 +687,7 @@ fn render_variant_after_name(
|
|||
data: &VariantData,
|
||||
f: &mut HirFormatter<'_>,
|
||||
field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
layout: &Layout,
|
||||
subst: &Substitution,
|
||||
b: &[u8],
|
||||
|
|
@ -695,7 +698,7 @@ fn render_variant_after_name(
|
|||
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
|
||||
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
|
||||
let ty = field_types[id].clone().substitute(Interner, subst);
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
|
|||
|
|
@ -1665,6 +1665,7 @@ impl InferenceContext<'_> {
|
|||
// the parameter to coerce to the expected type (for example in
|
||||
// `coerce_unsize_expected_type_4`).
|
||||
let param_ty = self.normalize_associated_types_in(param_ty);
|
||||
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
||||
let expected = Expectation::rvalue_hint(self, expected_ty);
|
||||
// infer with the expected type we have...
|
||||
let ty = self.infer_expr_inner(arg, &expected);
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ impl<'a> InferenceTable<'a> {
|
|||
// and registering an obligation. But it needs chalk support, so we handle the most basic
|
||||
// case (a non associated const without generic parameters) manually.
|
||||
if subst.len(Interner) == 0 {
|
||||
if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
|
||||
if let Ok(eval) =
|
||||
self.db.const_eval((*c_id).into(), subst.clone(), None)
|
||||
{
|
||||
eval
|
||||
} else {
|
||||
|
|
@ -785,7 +786,7 @@ impl<'a> InferenceTable<'a> {
|
|||
crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()),
|
||||
// try to evaluate unevaluated const. Replace with new var if const eval failed.
|
||||
crate::ConstScalar::UnevaluatedConst(id, subst) => {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
eval
|
||||
} else {
|
||||
self.new_const_var(data.ty.clone())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Compute the binary representation of a type
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
|
||||
use hir_def::{
|
||||
layout::{
|
||||
|
|
@ -61,7 +60,6 @@ pub enum LayoutError {
|
|||
}
|
||||
|
||||
struct LayoutCx<'a> {
|
||||
krate: CrateId,
|
||||
target: &'a TargetDataLayout,
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +80,7 @@ fn layout_of_simd_ty(
|
|||
db: &dyn HirDatabase,
|
||||
id: StructId,
|
||||
subst: &Substitution,
|
||||
krate: CrateId,
|
||||
env: Arc<TraitEnvironment>,
|
||||
dl: &TargetDataLayout,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let fields = db.field_types(id.into());
|
||||
|
|
@ -111,7 +109,7 @@ fn layout_of_simd_ty(
|
|||
// * the homogeneous field type and the number of fields.
|
||||
let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
|
||||
// Extract the number of elements from the layout of the array field:
|
||||
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else {
|
||||
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else {
|
||||
user_error!("Array with non array layout");
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +120,7 @@ fn layout_of_simd_ty(
|
|||
};
|
||||
|
||||
// Compute the ABI of the element type:
|
||||
let e_ly = db.layout_of_ty(e_ty, krate)?;
|
||||
let e_ly = db.layout_of_ty(e_ty, env.clone())?;
|
||||
let Abi::Scalar(e_abi) = e_ly.abi else {
|
||||
user_error!("simd type with inner non scalar type");
|
||||
};
|
||||
|
|
@ -152,25 +150,25 @@ fn layout_of_simd_ty(
|
|||
pub fn layout_of_ty_query(
|
||||
db: &dyn HirDatabase,
|
||||
ty: Ty,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let krate = trait_env.krate;
|
||||
let Some(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = &*cx.current_data_layout();
|
||||
let trait_env = Arc::new(TraitEnvironment::empty(krate));
|
||||
let ty = normalize(db, trait_env, ty.clone());
|
||||
let ty = normalize(db, trait_env.clone(), ty.clone());
|
||||
let result = match ty.kind(Interner) {
|
||||
TyKind::Adt(AdtId(def), subst) => {
|
||||
if let hir_def::AdtId::StructId(s) = def {
|
||||
let data = db.struct_data(*s);
|
||||
let repr = data.repr.unwrap_or_default();
|
||||
if repr.simd() {
|
||||
return layout_of_simd_ty(db, *s, subst, krate, &target);
|
||||
return layout_of_simd_ty(db, *s, subst, trait_env.clone(), &target);
|
||||
}
|
||||
};
|
||||
return db.layout_of_adt(*def, subst.clone(), krate);
|
||||
return db.layout_of_adt(*def, subst.clone(), trait_env.clone());
|
||||
}
|
||||
TyKind::Scalar(s) => match s {
|
||||
chalk_ir::Scalar::Bool => Layout::scalar(
|
||||
|
|
@ -228,7 +226,7 @@ pub fn layout_of_ty_query(
|
|||
|
||||
let fields = tys
|
||||
.iter(Interner)
|
||||
.map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate))
|
||||
.map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<Vec<_>>();
|
||||
|
|
@ -238,7 +236,7 @@ pub fn layout_of_ty_query(
|
|||
let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
|
||||
"unevaluated or mistyped const generic parameter".to_string(),
|
||||
))? as u64;
|
||||
let element = db.layout_of_ty(element.clone(), krate)?;
|
||||
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
|
||||
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
|
||||
|
||||
let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
|
||||
|
|
@ -259,7 +257,7 @@ pub fn layout_of_ty_query(
|
|||
}
|
||||
}
|
||||
TyKind::Slice(element) => {
|
||||
let element = db.layout_of_ty(element.clone(), krate)?;
|
||||
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
|
||||
Layout {
|
||||
variants: Variants::Single { index: struct_variant_idx() },
|
||||
fields: FieldsShape::Array { stride: element.size, count: 0 },
|
||||
|
|
@ -335,7 +333,7 @@ pub fn layout_of_ty_query(
|
|||
match impl_trait_id {
|
||||
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
||||
let infer = db.infer(func.into());
|
||||
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate);
|
||||
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env.clone());
|
||||
}
|
||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
||||
return Err(LayoutError::NotImplemented)
|
||||
|
|
@ -351,7 +349,7 @@ pub fn layout_of_ty_query(
|
|||
.map(|it| {
|
||||
db.layout_of_ty(
|
||||
it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()),
|
||||
krate,
|
||||
trait_env.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
|
@ -377,7 +375,7 @@ pub fn layout_of_ty_recover(
|
|||
_: &dyn HirDatabase,
|
||||
_: &[String],
|
||||
_: &Ty,
|
||||
_: &CrateId,
|
||||
_: &Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::{cmp, ops::Bound};
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
|
|
@ -16,7 +15,7 @@ use crate::{
|
|||
db::HirDatabase,
|
||||
lang_items::is_unsafe_cell,
|
||||
layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
|
||||
Substitution,
|
||||
Substitution, TraitEnvironment,
|
||||
};
|
||||
|
||||
use super::LayoutCx;
|
||||
|
|
@ -29,17 +28,18 @@ pub fn layout_of_adt_query(
|
|||
db: &dyn HirDatabase,
|
||||
def: AdtId,
|
||||
subst: Substitution,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let krate = trait_env.krate;
|
||||
let Some(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
var.fields()
|
||||
.iter()
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate))
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let (variants, repr) = match def {
|
||||
|
|
@ -134,7 +134,7 @@ pub fn layout_of_adt_recover(
|
|||
_: &[String],
|
||||
_: &AdtId,
|
||||
_: &Substitution,
|
||||
_: &CrateId,
|
||||
_: &Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
);
|
||||
|
||||
let (db, file_ids) = TestDB::with_many_files(&ra_fixture);
|
||||
let (adt_or_type_alias_id, module_id) = file_ids
|
||||
let adt_or_type_alias_id = file_ids
|
||||
.into_iter()
|
||||
.find_map(|file_id| {
|
||||
let module_id = db.module_for_file(file_id);
|
||||
|
|
@ -47,7 +47,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
}
|
||||
_ => None,
|
||||
})?;
|
||||
Some((adt_or_type_alias_id, module_id))
|
||||
Some(adt_or_type_alias_id)
|
||||
})
|
||||
.unwrap();
|
||||
let goal_ty = match adt_or_type_alias_id {
|
||||
|
|
@ -58,7 +58,13 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner))
|
||||
}
|
||||
};
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
db.layout_of_ty(
|
||||
goal_ty,
|
||||
db.trait_environment(match adt_or_type_alias_id {
|
||||
Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
|
||||
Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
|
||||
|
|
@ -72,7 +78,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
let adt_id = scope
|
||||
let function_id = scope
|
||||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::FunctionId(x) => {
|
||||
|
|
@ -82,11 +88,11 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
let hir_body = db.body(adt_id.into());
|
||||
let hir_body = db.body(function_id.into());
|
||||
let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0;
|
||||
let infer = db.infer(adt_id.into());
|
||||
let infer = db.infer(function_id.into());
|
||||
let goal_ty = infer.type_of_binding[b].clone();
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -665,13 +665,21 @@ pub fn is_dyn_method(
|
|||
};
|
||||
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||
if let TyKind::Dyn(d) = self_ty.kind(Interner) {
|
||||
let is_my_trait_in_bounds =
|
||||
d.bounds.skip_binders().as_slice(Interner).iter().any(|it| match it.skip_binders() {
|
||||
// rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
|
||||
// what the generics are, we are sure that the method is come from the vtable.
|
||||
WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id,
|
||||
_ => false,
|
||||
});
|
||||
let is_my_trait_in_bounds = d
|
||||
.bounds
|
||||
.skip_binders()
|
||||
.as_slice(Interner)
|
||||
.iter()
|
||||
.map(|it| it.skip_binders())
|
||||
.flat_map(|it| match it {
|
||||
WhereClause::Implemented(tr) => {
|
||||
all_super_traits(db.upcast(), from_chalk_trait_id(tr.trait_id))
|
||||
}
|
||||
_ => smallvec![],
|
||||
})
|
||||
// rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
|
||||
// what the generics are, we are sure that the method is come from the vtable.
|
||||
.any(|x| x == trait_id);
|
||||
if is_my_trait_in_bounds {
|
||||
return Some(fn_params);
|
||||
}
|
||||
|
|
@ -1504,7 +1512,7 @@ fn autoderef_method_receiver(
|
|||
ty: Ty,
|
||||
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
||||
let mut deref_chain: Vec<_> = Vec::new();
|
||||
let mut autoderef = autoderef::Autoderef::new(table, ty, true);
|
||||
let mut autoderef = autoderef::Autoderef::new(table, ty, false);
|
||||
while let Some((ty, derefs)) = autoderef.next() {
|
||||
deref_chain.push((
|
||||
autoderef.table.canonicalize(ty).value,
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
|
||||
krate: CrateId,
|
||||
) -> Ty {
|
||||
if matches!(base.data(Interner).kind, TyKind::Alias(_) | TyKind::AssociatedType(..)) {
|
||||
if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
|
||||
base = normalize(
|
||||
db,
|
||||
// FIXME: we should get this from caller
|
||||
|
|
@ -151,7 +151,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
);
|
||||
}
|
||||
match self {
|
||||
ProjectionElem::Deref => match &base.data(Interner).kind {
|
||||
ProjectionElem::Deref => match &base.kind(Interner) {
|
||||
TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
|
||||
TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
|
||||
subst.at(Interner, 0).assert_ty_ref(Interner).clone()
|
||||
|
|
@ -161,7 +161,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
return TyKind::Error.intern(Interner);
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(f) => match &base.data(Interner).kind {
|
||||
ProjectionElem::Field(f) => match &base.kind(Interner) {
|
||||
TyKind::Adt(_, subst) => {
|
||||
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
return TyKind::Error.intern(Interner);
|
||||
}
|
||||
},
|
||||
ProjectionElem::TupleOrClosureField(f) => match &base.data(Interner).kind {
|
||||
ProjectionElem::TupleOrClosureField(f) => match &base.kind(Interner) {
|
||||
TyKind::Tuple(_, subst) => subst
|
||||
.as_slice(Interner)
|
||||
.get(*f)
|
||||
|
|
@ -187,7 +187,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
}
|
||||
},
|
||||
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
|
||||
match &base.data(Interner).kind {
|
||||
match &base.kind(Interner) {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
|
||||
_ => {
|
||||
never!("Overloaded index is not a projection");
|
||||
|
|
@ -195,7 +195,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
&ProjectionElem::Subslice { from, to } => match &base.data(Interner).kind {
|
||||
&ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
|
||||
TyKind::Array(inner, c) => {
|
||||
let next_c = usize_const(
|
||||
db,
|
||||
|
|
|
|||
|
|
@ -484,9 +484,10 @@ pub fn interpret_mir(
|
|||
// a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
|
||||
// (and probably should) do better here, for example by excluding bindings outside of the target expression.
|
||||
assert_placeholder_ty_is_unused: bool,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> (Result<Const>, String, String) {
|
||||
let ty = body.locals[return_slot()].ty.clone();
|
||||
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused);
|
||||
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env);
|
||||
let it: Result<Const> = (|| {
|
||||
if evaluator.ptr_size() != std::mem::size_of::<usize>() {
|
||||
not_supported!("targets with different pointer size from host");
|
||||
|
|
@ -512,9 +513,9 @@ impl Evaluator<'_> {
|
|||
db: &'a dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
assert_placeholder_ty_is_unused: bool,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> Evaluator<'a> {
|
||||
let crate_id = owner.module(db.upcast()).krate();
|
||||
let trait_env = db.trait_environment_for_body(owner);
|
||||
Evaluator {
|
||||
stack: vec![0],
|
||||
heap: vec![0],
|
||||
|
|
@ -524,7 +525,7 @@ impl Evaluator<'_> {
|
|||
static_locations: HashMap::default(),
|
||||
db,
|
||||
random_state: oorandom::Rand64::new(0),
|
||||
trait_env,
|
||||
trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)),
|
||||
crate_id,
|
||||
stdout: vec![],
|
||||
stderr: vec![],
|
||||
|
|
@ -634,7 +635,7 @@ impl Evaluator<'_> {
|
|||
addr = addr.offset(ty_size * offset);
|
||||
}
|
||||
&ProjectionElem::Subslice { from, to } => {
|
||||
let inner_ty = match &ty.data(Interner).kind {
|
||||
let inner_ty = match &ty.kind(Interner) {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
|
||||
_ => TyKind::Error.intern(Interner),
|
||||
};
|
||||
|
|
@ -694,14 +695,14 @@ impl Evaluator<'_> {
|
|||
}
|
||||
let r = self
|
||||
.db
|
||||
.layout_of_ty(ty.clone(), self.crate_id)
|
||||
.layout_of_ty(ty.clone(), self.trait_env.clone())
|
||||
.map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?;
|
||||
self.layout_cache.borrow_mut().insert(ty.clone(), r.clone());
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
|
||||
self.db.layout_of_adt(adt, subst.clone(), self.crate_id).map_err(|e| {
|
||||
self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| {
|
||||
MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
|
||||
})
|
||||
}
|
||||
|
|
@ -793,7 +794,7 @@ impl Evaluator<'_> {
|
|||
.iter()
|
||||
.map(|it| self.operand_ty_and_eval(it, &mut locals))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let stack_frame = match &fn_ty.data(Interner).kind {
|
||||
let stack_frame = match &fn_ty.kind(Interner) {
|
||||
TyKind::Function(_) => {
|
||||
let bytes = self.eval_operand(func, &mut locals)?;
|
||||
self.exec_fn_pointer(
|
||||
|
|
@ -1255,7 +1256,7 @@ impl Evaluator<'_> {
|
|||
PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {
|
||||
let current_ty = self.operand_ty(operand, locals)?;
|
||||
if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) =
|
||||
¤t_ty.data(Interner).kind
|
||||
¤t_ty.kind(Interner)
|
||||
{
|
||||
let id = self.vtable_map.id(current_ty);
|
||||
let ptr_size = self.ptr_size();
|
||||
|
|
@ -1408,8 +1409,8 @@ impl Evaluator<'_> {
|
|||
addr: Interval,
|
||||
) -> Result<IntervalOrOwned> {
|
||||
use IntervalOrOwned::*;
|
||||
Ok(match &target_ty.data(Interner).kind {
|
||||
TyKind::Slice(_) => match ¤t_ty.data(Interner).kind {
|
||||
Ok(match &target_ty.kind(Interner) {
|
||||
TyKind::Slice(_) => match ¤t_ty.kind(Interner) {
|
||||
TyKind::Array(_, size) => {
|
||||
let len = match try_const_usize(self.db, size) {
|
||||
None => {
|
||||
|
|
@ -1435,7 +1436,7 @@ impl Evaluator<'_> {
|
|||
r.extend(vtable.to_le_bytes().into_iter());
|
||||
Owned(r)
|
||||
}
|
||||
TyKind::Adt(id, target_subst) => match ¤t_ty.data(Interner).kind {
|
||||
TyKind::Adt(id, target_subst) => match ¤t_ty.kind(Interner) {
|
||||
TyKind::Adt(current_id, current_subst) => {
|
||||
if id != current_id {
|
||||
not_supported!("unsizing struct with different type");
|
||||
|
|
@ -1582,10 +1583,13 @@ impl Evaluator<'_> {
|
|||
const_id = hir_def::GeneralConstId::ConstId(c);
|
||||
subst = s;
|
||||
}
|
||||
result_owner = self.db.const_eval(const_id.into(), subst).map_err(|e| {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
MirEvalError::ConstEvalError(name, Box::new(e))
|
||||
})?;
|
||||
result_owner = self
|
||||
.db
|
||||
.const_eval(const_id.into(), subst, Some(self.trait_env.clone()))
|
||||
.map_err(|e| {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
MirEvalError::ConstEvalError(name, Box::new(e))
|
||||
})?;
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
|
||||
if let ConstScalar::Bytes(v, mm) = &c.interned {
|
||||
break 'b (v, mm);
|
||||
|
|
@ -1818,9 +1822,13 @@ impl Evaluator<'_> {
|
|||
}
|
||||
AdtId::EnumId(e) => {
|
||||
let layout = this.layout(ty)?;
|
||||
if let Some((v, l)) =
|
||||
detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e)
|
||||
{
|
||||
if let Some((v, l)) = detect_variant_from_bytes(
|
||||
&layout,
|
||||
this.db,
|
||||
this.trait_env.clone(),
|
||||
bytes,
|
||||
e,
|
||||
) {
|
||||
let data = &this.db.enum_data(e).variants[v].variant_data;
|
||||
let field_types = this
|
||||
.db
|
||||
|
|
@ -1931,7 +1939,7 @@ impl Evaluator<'_> {
|
|||
) -> Result<Option<StackFrame>> {
|
||||
let id = from_bytes!(usize, bytes.get(self)?);
|
||||
let next_ty = self.vtable_map.ty(id)?.clone();
|
||||
match &next_ty.data(Interner).kind {
|
||||
match &next_ty.kind(Interner) {
|
||||
TyKind::FnDef(def, generic_args) => {
|
||||
self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span)
|
||||
}
|
||||
|
|
@ -2182,7 +2190,7 @@ impl Evaluator<'_> {
|
|||
let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?;
|
||||
func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size };
|
||||
}
|
||||
match &func_ty.data(Interner).kind {
|
||||
match &func_ty.kind(Interner) {
|
||||
TyKind::FnDef(def, subst) => {
|
||||
return self.exec_fn_def(
|
||||
*def,
|
||||
|
|
@ -2409,7 +2417,7 @@ pub fn render_const_using_debug_impl(
|
|||
owner: ConstId,
|
||||
c: &Const,
|
||||
) -> Result<String> {
|
||||
let mut evaluator = Evaluator::new(db, owner.into(), false);
|
||||
let mut evaluator = Evaluator::new(db, owner.into(), false, None);
|
||||
let locals = &Locals {
|
||||
ptr: ArenaMap::new(),
|
||||
body: db
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
|
|||
db.trait_environment(func_id.into()),
|
||||
)
|
||||
.map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?;
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false, None);
|
||||
result?;
|
||||
Ok((stdout, stderr))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
);
|
||||
}
|
||||
let callee_ty = self.expr_ty_after_adjustments(*callee);
|
||||
match &callee_ty.data(Interner).kind {
|
||||
match &callee_ty.kind(Interner) {
|
||||
chalk_ir::TyKind::FnDef(..) => {
|
||||
let func = Operand::from_bytes(vec![], callee_ty.clone());
|
||||
self.lower_call_and_args(
|
||||
|
|
@ -1229,7 +1229,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
}
|
||||
Expr::Array(l) => match l {
|
||||
Array::ElementList { elements, .. } => {
|
||||
let elem_ty = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
|
||||
let elem_ty = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
|
||||
TyKind::Array(ty, _) => ty.clone(),
|
||||
_ => {
|
||||
return Err(MirLowerError::TypeError(
|
||||
|
|
@ -1260,7 +1260,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
|
||||
let len = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
|
||||
TyKind::Array(_, len) => len.clone(),
|
||||
_ => {
|
||||
return Err(MirLowerError::TypeError(
|
||||
|
|
@ -1341,7 +1341,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<Operand> {
|
||||
let size = self
|
||||
.db
|
||||
.layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())?
|
||||
.layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))?
|
||||
.size
|
||||
.bytes_usize();
|
||||
let bytes = match l {
|
||||
|
|
@ -1355,7 +1355,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
return Ok(Operand::from_concrete_const(data, mm, ty));
|
||||
}
|
||||
hir_def::hir::Literal::CString(b) => {
|
||||
let b = b.as_bytes();
|
||||
let bytes = b.iter().copied().chain(iter::once(0)).collect::<Vec<_>>();
|
||||
|
||||
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
|
||||
|
|
@ -1418,7 +1417,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
} else {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
self.db
|
||||
.const_eval(const_id.into(), subst)
|
||||
.const_eval(const_id.into(), subst, None)
|
||||
.map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
|
||||
};
|
||||
Ok(Operand::Constant(c))
|
||||
|
|
|
|||
|
|
@ -1236,6 +1236,27 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inherent_method_ref_self_deref_raw() {
|
||||
check_types(
|
||||
r#"
|
||||
struct Val;
|
||||
|
||||
impl Val {
|
||||
pub fn method(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo: *const Val;
|
||||
foo.method();
|
||||
// ^^^^^^^^^^^^ {unknown}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_method_deref_raw() {
|
||||
check_types(
|
||||
|
|
|
|||
|
|
@ -4434,3 +4434,47 @@ fn test(v: S<i32>) {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn associated_type_in_argument() {
|
||||
check(
|
||||
r#"
|
||||
trait A {
|
||||
fn m(&self) -> i32;
|
||||
}
|
||||
|
||||
fn x<T: B>(k: &<T as B>::Ty) {
|
||||
k.m();
|
||||
}
|
||||
|
||||
struct X;
|
||||
struct Y;
|
||||
|
||||
impl A for X {
|
||||
fn m(&self) -> i32 {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
impl A for Y {
|
||||
fn m(&self) -> i32 {
|
||||
32
|
||||
}
|
||||
}
|
||||
|
||||
trait B {
|
||||
type Ty: A;
|
||||
}
|
||||
|
||||
impl B for u16 {
|
||||
type Ty = X;
|
||||
}
|
||||
|
||||
fn ttt() {
|
||||
let inp = Y;
|
||||
x::<u16>(&inp);
|
||||
//^^^^ expected &X, got &Y
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,15 @@ use intern::Interned;
|
|||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
consteval::unknown_const,
|
||||
db::HirDatabase,
|
||||
layout::{Layout, TagEncoding},
|
||||
mir::pad16,
|
||||
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
|
||||
Ty, WhereClause,
|
||||
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitEnvironment,
|
||||
TraitRef, TraitRefExt, Ty, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) fn fn_traits(
|
||||
|
|
@ -417,7 +418,7 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
|||
) -> Result<Const, Self::Error> {
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
|
||||
if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
return Ok(eval);
|
||||
} else {
|
||||
return Ok(unknown_const(constant.data(Interner).ty.clone()));
|
||||
|
|
@ -431,10 +432,11 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
|||
pub(crate) fn detect_variant_from_bytes<'a>(
|
||||
layout: &'a Layout,
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
b: &[u8],
|
||||
e: EnumId,
|
||||
) -> Option<(LocalEnumVariantId, &'a Layout)> {
|
||||
let krate = trait_env.krate;
|
||||
let (var_id, var_layout) = match &layout.variants {
|
||||
hir_def::layout::Variants::Single { index } => (index.0, &*layout),
|
||||
hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
|
|
|
|||
|
|
@ -378,11 +378,6 @@ impl ModuleDef {
|
|||
ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
|
||||
};
|
||||
|
||||
let module = match self.module(db) {
|
||||
Some(it) => it,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
|
||||
let mut acc = Vec::new();
|
||||
|
||||
match self.as_def_with_body() {
|
||||
|
|
@ -390,7 +385,7 @@ impl ModuleDef {
|
|||
def.diagnostics(db, &mut acc);
|
||||
}
|
||||
None => {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, id) {
|
||||
acc.push(diag.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -965,8 +960,15 @@ impl Field {
|
|||
}
|
||||
|
||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
|
||||
db.layout_of_ty(
|
||||
self.ty(db).ty.clone(),
|
||||
db.trait_environment(match hir_def::VariantId::from(self.parent) {
|
||||
hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id),
|
||||
hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
|
||||
hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
|
||||
}),
|
||||
)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
|
||||
}
|
||||
|
||||
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
|
||||
|
|
@ -1246,8 +1248,12 @@ impl Adt {
|
|||
return Err(LayoutError::HasPlaceholder);
|
||||
}
|
||||
let krate = self.krate(db).id;
|
||||
db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
|
||||
db.layout_of_adt(
|
||||
self.into(),
|
||||
Substitution::empty(Interner),
|
||||
db.trait_environment(self.into()),
|
||||
)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
|
||||
}
|
||||
|
||||
/// Turns this ADT into a type. Any type parameters of the ADT will be
|
||||
|
|
@ -1820,7 +1826,7 @@ impl DefWithBody {
|
|||
// FIXME: don't ignore diagnostics for in type const
|
||||
DefWithBody::InTypeConst(_) => return,
|
||||
};
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
|
||||
acc.push(diag.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -1987,7 +1993,7 @@ impl Function {
|
|||
return r;
|
||||
}
|
||||
};
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false, None);
|
||||
let mut text = match result {
|
||||
Ok(_) => "pass".to_string(),
|
||||
Err(e) => {
|
||||
|
|
@ -2156,7 +2162,7 @@ impl Const {
|
|||
}
|
||||
|
||||
pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
|
||||
let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
|
||||
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
|
||||
let data = &c.data(Interner);
|
||||
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
|
||||
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
|
||||
|
|
@ -4322,7 +4328,7 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||
db.layout_of_ty(self.ty.clone(), self.env.krate)
|
||||
db.layout_of_ty(self.ty.clone(), self.env.clone())
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use syntax::{
|
|||
ast::{self, HasName, HasVisibility},
|
||||
AstNode,
|
||||
SyntaxKind::{
|
||||
CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
|
||||
self, ASSOC_ITEM_LIST, CONST, ENUM, FN, MACRO_DEF, MODULE, SOURCE_FILE, STATIC, STRUCT,
|
||||
TRAIT, TYPE_ALIAS, USE, VISIBILITY,
|
||||
},
|
||||
T,
|
||||
SyntaxNode, T,
|
||||
};
|
||||
|
||||
use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
|
||||
|
|
@ -46,13 +47,11 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
|||
|
||||
let (offset, target) = if let Some(keyword) = item_keyword {
|
||||
let parent = keyword.parent()?;
|
||||
let def_kws =
|
||||
vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
|
||||
// Parent is not a definition, can't add visibility
|
||||
if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
|
||||
|
||||
if !can_add(&parent) {
|
||||
return None;
|
||||
}
|
||||
// Already have visibility, do nothing
|
||||
// Already has visibility, do nothing
|
||||
if parent.children().any(|child| child.kind() == VISIBILITY) {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -86,6 +85,29 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
|||
)
|
||||
}
|
||||
|
||||
fn can_add(node: &SyntaxNode) -> bool {
|
||||
const LEGAL: &[SyntaxKind] =
|
||||
&[CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
|
||||
|
||||
LEGAL.contains(&node.kind()) && {
|
||||
let Some(p) = node.parent() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if p.kind() == ASSOC_ITEM_LIST {
|
||||
p.parent()
|
||||
.and_then(|it| ast::Impl::cast(it))
|
||||
// inherent impls i.e 'non-trait impls' have a non-local
|
||||
// effect, thus can have visibility even when nested.
|
||||
// so filter them out
|
||||
.filter(|imp| imp.for_token().is_none())
|
||||
.is_some()
|
||||
} else {
|
||||
matches!(p.kind(), SOURCE_FILE | MODULE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
|
||||
if vis.syntax().text() == "pub" {
|
||||
let target = vis.syntax().text_range();
|
||||
|
|
@ -129,6 +151,16 @@ mod tests {
|
|||
check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
|
||||
check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}");
|
||||
check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;");
|
||||
check_assist(
|
||||
change_visibility,
|
||||
"impl Foo { f$0n foo() {} }",
|
||||
"impl Foo { pub(crate) fn foo() {} }",
|
||||
);
|
||||
check_assist(
|
||||
change_visibility,
|
||||
"fn bar() { impl Foo { f$0n foo() {} } }",
|
||||
"fn bar() { impl Foo { pub(crate) fn foo() {} } }",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -213,4 +245,33 @@ mod tests {
|
|||
check_assist_target(change_visibility, "pub(crate)$0 fn foo() {}", "pub(crate)");
|
||||
check_assist_target(change_visibility, "struct S { $0field: u32 }", "field");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_for_items_within_traits() {
|
||||
check_assist_not_applicable(change_visibility, "trait Foo { f$0n run() {} }");
|
||||
check_assist_not_applicable(change_visibility, "trait Foo { con$0st FOO: u8 = 69; }");
|
||||
check_assist_not_applicable(change_visibility, "impl Foo for Bar { f$0n quox() {} }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_for_items_within_fns() {
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { unsafe f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { const f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { con$0st FOO: u8 = 69; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { en$0um Foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { stru$0ct Foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { mo$0d foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { $0use foo; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { $0type Foo = Bar<T>; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { tr$0ait Foo {} }");
|
||||
check_assist_not_applicable(
|
||||
change_visibility,
|
||||
"fn foo() { impl Trait for Bar { f$0n bar() {} } }",
|
||||
);
|
||||
check_assist_not_applicable(
|
||||
change_visibility,
|
||||
"fn foo() { impl Trait for Bar { con$0st FOO: u8 = 69; } }",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -545,4 +545,100 @@ pub static SomeStatic: u8 = 10;
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
fn main() {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
let INNER_INNER = 42;
|
||||
//^^^^^^^^^^^ 💡 warn: Variable `INNER_INNER` should have snake_case name, e.g. `inner_inner`
|
||||
}
|
||||
|
||||
let INNER_LOCAL = 42;
|
||||
//^^^^^^^^^^^ 💡 warn: Variable `INNER_LOCAL` should have snake_case name, e.g. `inner_local`
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_body_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
const _: () = {
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
|
||||
const foo: () = {
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
};
|
||||
};
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_body_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
static FOO: () = {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
|
||||
static bar: () = {
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
};
|
||||
};
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_variant_body_inner_item() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
enum E {
|
||||
A = {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
42
|
||||
},
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use syntax::{
|
|||
|
||||
use crate::{
|
||||
syntax_highlighting::{
|
||||
escape::{highlight_escape_char, highlight_escape_string},
|
||||
escape::{highlight_escape_byte, highlight_escape_char, highlight_escape_string},
|
||||
format::highlight_format_string,
|
||||
highlights::Highlights,
|
||||
macro_::MacroHighlighter,
|
||||
|
|
@ -471,6 +471,14 @@ fn traverse(
|
|||
};
|
||||
|
||||
highlight_escape_char(hl, &char, range.start())
|
||||
} else if ast::Byte::can_cast(token.kind())
|
||||
&& ast::Byte::can_cast(descended_token.kind())
|
||||
{
|
||||
let Some(byte) = ast::Byte::cast(token) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
highlight_escape_byte(hl, &byte, range.start())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Syntax highlighting for escape sequences
|
||||
use crate::syntax_highlighting::highlights::Highlights;
|
||||
use crate::{HlRange, HlTag};
|
||||
use syntax::ast::{Char, IsString};
|
||||
use syntax::ast::{Byte, Char, IsString};
|
||||
use syntax::{AstToken, TextRange, TextSize};
|
||||
|
||||
pub(super) fn highlight_escape_string<T: IsString>(
|
||||
|
|
@ -10,14 +10,14 @@ pub(super) fn highlight_escape_string<T: IsString>(
|
|||
start: TextSize,
|
||||
) {
|
||||
string.escaped_char_ranges(&mut |piece_range, char| {
|
||||
if char.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
if string.text()[piece_range.start().into()..].starts_with('\\') {
|
||||
let highlight = match char {
|
||||
Ok(_) => HlTag::EscapeSequence,
|
||||
Err(_) => HlTag::InvalidEscapeSequence,
|
||||
};
|
||||
stack.add(HlRange {
|
||||
range: piece_range + start,
|
||||
highlight: HlTag::EscapeSequence.into(),
|
||||
highlight: highlight.into(),
|
||||
binding_hash: None,
|
||||
});
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ pub(super) fn highlight_escape_string<T: IsString>(
|
|||
|
||||
pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
|
||||
if char.value().is_none() {
|
||||
// We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
|
||||
// state and this token contains junks, since `'` is not a reliable delimiter (consider
|
||||
// lifetimes). Nonetheless, parser errors should already be emitted.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -43,3 +46,24 @@ pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start:
|
|||
TextRange::new(start + TextSize::from(1), start + TextSize::from(text.len() as u32 + 1));
|
||||
stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
|
||||
}
|
||||
|
||||
pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) {
|
||||
if byte.value().is_none() {
|
||||
// See `highlight_escape_char` for why no error highlighting here.
|
||||
return;
|
||||
}
|
||||
|
||||
let text = byte.text();
|
||||
if !text.starts_with("b'") || !text.ends_with('\'') {
|
||||
return;
|
||||
}
|
||||
|
||||
let text = &text[2..text.len() - 1];
|
||||
if !text.starts_with('\\') {
|
||||
return;
|
||||
}
|
||||
|
||||
let range =
|
||||
TextRange::new(start + TextSize::from(2), start + TextSize::from(text.len() as u32 + 2));
|
||||
stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ pub enum HlTag {
|
|||
Comment,
|
||||
EscapeSequence,
|
||||
FormatSpecifier,
|
||||
InvalidEscapeSequence,
|
||||
Keyword,
|
||||
NumericLiteral,
|
||||
Operator(HlOperator),
|
||||
|
|
@ -166,6 +167,7 @@ impl HlTag {
|
|||
HlTag::CharLiteral => "char_literal",
|
||||
HlTag::Comment => "comment",
|
||||
HlTag::EscapeSequence => "escape_sequence",
|
||||
HlTag::InvalidEscapeSequence => "invalid_escape_sequence",
|
||||
HlTag::FormatSpecifier => "format_specifier",
|
||||
HlTag::Keyword => "keyword",
|
||||
HlTag::Punctuation(punct) => match punct {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
|
||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root library">foo</span><span class="semicolon">;</span>
|
||||
<span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">//! This is a module to test doc injection.</span>
|
||||
<span class="comment documentation">//! ```</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
|
||||
<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
|
||||
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code>
|
||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="module crate_root library">proc_macros</span><span class="operator">::</span><span class="macro library">mirror</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
|
||||
<span class="brace macro">{</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
|
||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
|
||||
<span class="comment documentation">/// This is an intra doc injection test for modules</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||
<span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">>></span> <span class="numeric_literal">1</span> <span class="bitwise"><<</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
|
||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span>
|
||||
|
|
@ -105,6 +106,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x65</span><span class="char_literal">'</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x00</span><span class="char_literal">'</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="byte_literal">b'</span><span class="escape_sequence">\xFF</span><span class="byte_literal">'</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span>
|
||||
|
|
@ -159,8 +162,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="invalid_escape_sequence">\xFF</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// invalid non-UTF8 escape sequences</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\xFF</span><span class="invalid_escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, invalid unicodes</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
|
||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span>
|
||||
|
|
|
|||
|
|
@ -451,6 +451,8 @@ fn main() {
|
|||
let a = '\x65';
|
||||
let a = '\x00';
|
||||
|
||||
let a = b'\xFF';
|
||||
|
||||
println!("Hello {{Hello}}");
|
||||
// from https://doc.rust-lang.org/std/fmt/index.html
|
||||
println!("Hello"); // => "Hello"
|
||||
|
|
@ -505,8 +507,9 @@ fn main() {
|
|||
println!("Hello\nWorld");
|
||||
println!("\u{48}\x65\x6C\x6C\x6F World");
|
||||
|
||||
let _ = "\x28\x28\x00\x63\n";
|
||||
let _ = b"\x28\x28\x00\x63\n";
|
||||
let _ = "\x28\x28\x00\x63\xFF\u{FF}\n"; // invalid non-UTF8 escape sequences
|
||||
let _ = b"\x28\x28\x00\x63\xFF\u{FF}\n"; // valid bytes, invalid unicodes
|
||||
let _ = c"\u{FF}\xFF"; // valid bytes, valid unicodes
|
||||
let backslash = r"\\";
|
||||
|
||||
println!("{\x41}", A = 92);
|
||||
|
|
|
|||
|
|
@ -211,70 +211,54 @@ impl BlockLike {
|
|||
const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
|
||||
|
||||
fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
|
||||
match p.current() {
|
||||
T![pub] => {
|
||||
let m = p.start();
|
||||
p.bump(T![pub]);
|
||||
if p.at(T!['(']) {
|
||||
match p.nth(1) {
|
||||
// test crate_visibility
|
||||
// pub(crate) struct S;
|
||||
// pub(self) struct S;
|
||||
// pub(super) struct S;
|
||||
if !p.at(T![pub]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test_err crate_visibility_empty_recover
|
||||
// pub() struct S;
|
||||
let m = p.start();
|
||||
p.bump(T![pub]);
|
||||
if p.at(T!['(']) {
|
||||
match p.nth(1) {
|
||||
// test crate_visibility
|
||||
// pub(crate) struct S;
|
||||
// pub(self) struct S;
|
||||
// pub(super) struct S;
|
||||
|
||||
// test pub_parens_typepath
|
||||
// struct B(pub (super::A));
|
||||
// struct B(pub (crate::A,));
|
||||
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
|
||||
// If we are in a tuple struct, then the parens following `pub`
|
||||
// might be an tuple field, not part of the visibility. So in that
|
||||
// case we don't want to consume an identifier.
|
||||
// test_err crate_visibility_empty_recover
|
||||
// pub() struct S;
|
||||
|
||||
// test pub_tuple_field
|
||||
// struct MyStruct(pub (u32, u32));
|
||||
// struct MyStruct(pub (u32));
|
||||
// struct MyStruct(pub ());
|
||||
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
|
||||
p.bump(T!['(']);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
}
|
||||
// test crate_visibility_in
|
||||
// pub(in super::A) struct S;
|
||||
// pub(in crate) struct S;
|
||||
T![in] => {
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![in]);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
_ => {}
|
||||
// test pub_parens_typepath
|
||||
// struct B(pub (super::A));
|
||||
// struct B(pub (crate::A,));
|
||||
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
|
||||
// If we are in a tuple struct, then the parens following `pub`
|
||||
// might be an tuple field, not part of the visibility. So in that
|
||||
// case we don't want to consume an identifier.
|
||||
|
||||
// test pub_tuple_field
|
||||
// struct MyStruct(pub (u32, u32));
|
||||
// struct MyStruct(pub (u32));
|
||||
// struct MyStruct(pub ());
|
||||
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
|
||||
p.bump(T!['(']);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
}
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
}
|
||||
// test crate_keyword_vis
|
||||
// crate fn main() { }
|
||||
// struct S { crate field: u32 }
|
||||
// struct T(crate u32);
|
||||
T![crate] => {
|
||||
if p.nth_at(1, T![::]) {
|
||||
// test crate_keyword_path
|
||||
// fn foo() { crate::foo(); }
|
||||
return false;
|
||||
// test crate_visibility_in
|
||||
// pub(in super::A) struct S;
|
||||
// pub(in crate) struct S;
|
||||
T![in] => {
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![in]);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
let m = p.start();
|
||||
p.bump(T![crate]);
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
_ => {}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
}
|
||||
|
||||
fn opt_rename(p: &mut Parser<'_>) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ fn vis() {
|
|||
check(PrefixEntryPoint::Vis, "fn foo() {}", "");
|
||||
check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
|
||||
check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
|
||||
check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
SOURCE_FILE
|
||||
FN
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
FN_KW "fn"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "main"
|
||||
PARAM_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
STRUCT
|
||||
STRUCT_KW "struct"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "S"
|
||||
WHITESPACE " "
|
||||
RECORD_FIELD_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
RECORD_FIELD
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "field"
|
||||
COLON ":"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u32"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
STRUCT
|
||||
STRUCT_KW "struct"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "T"
|
||||
TUPLE_FIELD_LIST
|
||||
L_PAREN "("
|
||||
TUPLE_FIELD
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u32"
|
||||
R_PAREN ")"
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n"
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
crate fn main() { }
|
||||
struct S { crate field: u32 }
|
||||
struct T(crate u32);
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
SOURCE_FILE
|
||||
FN
|
||||
FN_KW "fn"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "foo"
|
||||
PARAM_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
EXPR_STMT
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
CRATE_KW "crate"
|
||||
COLON2 "::"
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "foo"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
SEMICOLON ";"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
|
|
@ -1 +0,0 @@
|
|||
fn foo() { crate::foo(); }
|
||||
|
|
@ -145,7 +145,7 @@ pub struct PackageDependency {
|
|||
pub kind: DepKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DepKind {
|
||||
/// Available to the library, binary, and dev targets in the package (but not the build script).
|
||||
Normal,
|
||||
|
|
@ -156,23 +156,20 @@ pub enum DepKind {
|
|||
}
|
||||
|
||||
impl DepKind {
|
||||
fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
|
||||
let mut dep_kinds = Vec::new();
|
||||
fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> {
|
||||
let mut dep_kinds = [None; 3];
|
||||
if list.is_empty() {
|
||||
dep_kinds.push(Self::Normal);
|
||||
dep_kinds[0] = Some(Self::Normal);
|
||||
}
|
||||
for info in list {
|
||||
let kind = match info.kind {
|
||||
cargo_metadata::DependencyKind::Normal => Self::Normal,
|
||||
cargo_metadata::DependencyKind::Development => Self::Dev,
|
||||
cargo_metadata::DependencyKind::Build => Self::Build,
|
||||
match info.kind {
|
||||
cargo_metadata::DependencyKind::Normal => dep_kinds[0] = Some(Self::Normal),
|
||||
cargo_metadata::DependencyKind::Development => dep_kinds[1] = Some(Self::Dev),
|
||||
cargo_metadata::DependencyKind::Build => dep_kinds[2] = Some(Self::Build),
|
||||
cargo_metadata::DependencyKind::Unknown => continue,
|
||||
};
|
||||
dep_kinds.push(kind);
|
||||
}
|
||||
}
|
||||
dep_kinds.sort_unstable();
|
||||
dep_kinds.dedup();
|
||||
dep_kinds.into_iter()
|
||||
dep_kinds.into_iter().flatten()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
|
||||
use hir::{
|
||||
db::{DefDatabase, ExpandDatabase, HirDatabase},
|
||||
Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ModuleDef, Name,
|
||||
Adt, AssocItem, Crate, DefWithBody, HasSource, HirDisplay, ModuleDef, Name,
|
||||
};
|
||||
use hir_def::{
|
||||
body::{BodySourceMap, SyntheticSyntax},
|
||||
|
|
@ -277,7 +277,7 @@ impl flags::AnalysisStats {
|
|||
let Err(e) = db.layout_of_adt(
|
||||
hir_def::AdtId::from(a).into(),
|
||||
Substitution::empty(Interner),
|
||||
a.krate(db).into(),
|
||||
db.trait_environment(a.into()),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ define_semantic_token_types![
|
|||
(DERIVE_HELPER, "deriveHelper") => DECORATOR,
|
||||
(DOT, "dot"),
|
||||
(ESCAPE_SEQUENCE, "escapeSequence") => STRING,
|
||||
(INVALID_ESCAPE_SEQUENCE, "invalidEscapeSequence") => STRING,
|
||||
(FORMAT_SPECIFIER, "formatSpecifier") => STRING,
|
||||
(GENERIC, "generic") => TYPE_PARAMETER,
|
||||
(LABEL, "label"),
|
||||
|
|
|
|||
|
|
@ -640,6 +640,7 @@ fn semantic_token_type_and_modifiers(
|
|||
HlTag::CharLiteral => semantic_tokens::CHAR,
|
||||
HlTag::Comment => semantic_tokens::COMMENT,
|
||||
HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
|
||||
HlTag::InvalidEscapeSequence => semantic_tokens::INVALID_ESCAPE_SEQUENCE,
|
||||
HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
|
||||
HlTag::Keyword => semantic_tokens::KEYWORD,
|
||||
HlTag::None => semantic_tokens::GENERIC,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
|
||||
use rustc_lexer::unescape::{
|
||||
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::{self, AstToken},
|
||||
|
|
@ -146,6 +148,7 @@ impl QuoteOffsets {
|
|||
|
||||
pub trait IsString: AstToken {
|
||||
const RAW_PREFIX: &'static str;
|
||||
const MODE: Mode;
|
||||
fn is_raw(&self) -> bool {
|
||||
self.text().starts_with(Self::RAW_PREFIX)
|
||||
}
|
||||
|
|
@ -181,7 +184,7 @@ pub trait IsString: AstToken {
|
|||
let text = &self.text()[text_range_no_quotes - start];
|
||||
let offset = text_range_no_quotes.start() - start;
|
||||
|
||||
unescape_literal(text, Mode::Str, &mut |range, unescaped_char| {
|
||||
unescape_literal(text, Self::MODE, &mut |range, unescaped_char| {
|
||||
let text_range =
|
||||
TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
|
||||
cb(text_range + offset, unescaped_char);
|
||||
|
|
@ -196,6 +199,7 @@ pub trait IsString: AstToken {
|
|||
|
||||
impl IsString for ast::String {
|
||||
const RAW_PREFIX: &'static str = "r";
|
||||
const MODE: Mode = Mode::Str;
|
||||
}
|
||||
|
||||
impl ast::String {
|
||||
|
|
@ -213,7 +217,7 @@ impl ast::String {
|
|||
let mut buf = String::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
|
||||
unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
|
|
@ -239,6 +243,7 @@ impl ast::String {
|
|||
|
||||
impl IsString for ast::ByteString {
|
||||
const RAW_PREFIX: &'static str = "br";
|
||||
const MODE: Mode = Mode::ByteStr;
|
||||
}
|
||||
|
||||
impl ast::ByteString {
|
||||
|
|
@ -256,7 +261,7 @@ impl ast::ByteString {
|
|||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
|
||||
unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
|
|
@ -282,42 +287,70 @@ impl ast::ByteString {
|
|||
|
||||
impl IsString for ast::CString {
|
||||
const RAW_PREFIX: &'static str = "cr";
|
||||
const MODE: Mode = Mode::CStr;
|
||||
|
||||
fn escaped_char_ranges(
|
||||
&self,
|
||||
cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
|
||||
) {
|
||||
let text_range_no_quotes = match self.text_range_between_quotes() {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let start = self.syntax().text_range().start();
|
||||
let text = &self.text()[text_range_no_quotes - start];
|
||||
let offset = text_range_no_quotes.start() - start;
|
||||
|
||||
unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| {
|
||||
let text_range =
|
||||
TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
|
||||
// XXX: This method should only be used for highlighting ranges. The unescaped
|
||||
// char/byte is not used. For simplicity, we return an arbitrary placeholder char.
|
||||
cb(text_range + offset, unescaped_char.map(|_| ' '));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::CString {
|
||||
pub fn value(&self) -> Option<Cow<'_, str>> {
|
||||
pub fn value(&self) -> Option<Cow<'_, [u8]>> {
|
||||
if self.is_raw() {
|
||||
let text = self.text();
|
||||
let text =
|
||||
&text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
return Some(Cow::Borrowed(text));
|
||||
return Some(Cow::Borrowed(text.as_bytes()));
|
||||
}
|
||||
|
||||
let text = self.text();
|
||||
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
|
||||
let mut buf = String::new();
|
||||
let mut buf = Vec::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
let mut char_buf = [0u8; 4];
|
||||
let mut extend_unit = |buf: &mut Vec<u8>, unit: CStrUnit| match unit {
|
||||
CStrUnit::Byte(b) => buf.push(b),
|
||||
CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()),
|
||||
};
|
||||
unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match (
|
||||
unescaped,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
(Ok(c), false) => buf.push(c),
|
||||
(Ok(u), false) => extend_unit(&mut buf, u),
|
||||
(Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
|
||||
prev_end = char_range.end
|
||||
}
|
||||
(Ok(c), true) => {
|
||||
(Ok(u), true) => {
|
||||
buf.reserve_exact(text.len());
|
||||
buf.push_str(&text[..prev_end]);
|
||||
buf.push(c);
|
||||
buf.extend(text[..prev_end].as_bytes());
|
||||
extend_unit(&mut buf, u);
|
||||
}
|
||||
(Err(_), _) => has_error = true,
|
||||
});
|
||||
|
||||
match (has_error, buf.capacity() == 0) {
|
||||
(true, _) => None,
|
||||
(false, true) => Some(Cow::Borrowed(text)),
|
||||
(false, true) => Some(Cow::Borrowed(text.as_bytes())),
|
||||
(false, false) => Some(Cow::Owned(buf)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -449,27 +449,24 @@ You'll need to close and reopen all .rs and Cargo files, or to restart the IDE,
|
|||
Support for the language server protocol is built into Kate through the LSP plugin, which is included by default.
|
||||
It is preconfigured to use rust-analyzer for Rust sources since Kate 21.12.
|
||||
|
||||
Earlier versions allow you to use rust-analyzer through a simple settings change.
|
||||
In the LSP Client settings of Kate, copy the content of the third tab "default parameters" to the second tab "server configuration".
|
||||
Then in the configuration replace:
|
||||
To change rust-analyzer config options, start from the following example and put it into Kate's "User Server Settings" tab (located under the LSP Client settings):
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"servers": {
|
||||
"rust": {
|
||||
"command": ["rls"],
|
||||
"rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
|
||||
"url": "https://github.com/rust-lang/rls",
|
||||
"highlightingModeRegex": "^Rust$"
|
||||
},
|
||||
----
|
||||
With
|
||||
[source,json]
|
||||
----
|
||||
"rust": {
|
||||
"command": ["rust-analyzer"],
|
||||
"rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
|
||||
"url": "https://github.com/rust-lang/rust-analyzer",
|
||||
"highlightingModeRegex": "^Rust$"
|
||||
},
|
||||
"initializationOptions": {
|
||||
"cachePriming": {
|
||||
"enable": false
|
||||
},
|
||||
"check": {
|
||||
"allTargets": false
|
||||
},
|
||||
"checkOnSave": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
Then click on apply, and restart the LSP server for your rust project.
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,12 @@
|
|||
"build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
|
||||
"build": "npm run build-base -- --sourcemap",
|
||||
"watch": "npm run build-base -- --sourcemap --watch",
|
||||
"lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
|
||||
"fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
|
||||
"pretest": "tsc && npm run build",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "eslint -c .eslintrc.js --ext ts ./src ./tests",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"typecheck": "tsc",
|
||||
"pretest": "npm run typecheck && npm run build",
|
||||
"test": "node ./out/tests/runTests.js"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -1801,12 +1804,16 @@
|
|||
},
|
||||
{
|
||||
"id": "escapeSequence",
|
||||
"description": "Style for char escapes in strings"
|
||||
"description": "Style for char or byte escapes in strings"
|
||||
},
|
||||
{
|
||||
"id": "formatSpecifier",
|
||||
"description": "Style for {} placeholders in format strings"
|
||||
},
|
||||
{
|
||||
"id": "invalidEscapeSequence",
|
||||
"description": "Style for invalid char or byte escapes in strings"
|
||||
},
|
||||
{
|
||||
"id": "label",
|
||||
"description": "Style for labels"
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
|
|||
return vscode.debug.startDebugging(undefined, debugConfig);
|
||||
}
|
||||
|
||||
function createCommandLink(extensionId: string): string {
|
||||
// do not remove the second quotes inside
|
||||
// encodeURIComponent or it won't work
|
||||
return `extension.open?${encodeURIComponent(`"${extensionId}"`)}`;
|
||||
}
|
||||
|
||||
async function getDebugConfiguration(
|
||||
ctx: Ctx,
|
||||
runnable: ra.Runnable,
|
||||
|
|
@ -90,9 +96,12 @@ async function getDebugConfiguration(
|
|||
}
|
||||
|
||||
if (!debugEngine) {
|
||||
const commandCodeLLDB: string = createCommandLink("vadimcn.vscode-lldb");
|
||||
const commandCpp: string = createCommandLink("ms-vscode.cpptools");
|
||||
|
||||
await vscode.window.showErrorMessage(
|
||||
`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)` +
|
||||
` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`,
|
||||
`Install [CodeLLDB](command:${commandCodeLLDB} "Open CodeLLDB")` +
|
||||
` or [C/C++](command:${commandCpp} "Open C/C++") extension for debugging.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# No undefined variables
|
||||
set -u
|
||||
|
|
|
|||
4282
src/tools/tidy/src/issues.txt
Normal file
4282
src/tools/tidy/src/issues.txt
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -3,14 +3,16 @@
|
|||
//! - there are no stray `.stderr` files
|
||||
|
||||
use ignore::Walk;
|
||||
use std::collections::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const ENTRY_LIMIT: usize = 900;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1894;
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1893;
|
||||
const ROOT_ENTRY_LIMIT: usize = 870;
|
||||
|
||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||
|
|
@ -88,6 +90,12 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
|
|||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
check_entries(&path, bad);
|
||||
|
||||
// the list of files in ui tests that are allowed to start with `issue-XXXX`
|
||||
let mut allowed_issue_filenames: HashSet<String> = HashSet::from(
|
||||
include!("issues.txt").map(|path| path.replace("/", std::path::MAIN_SEPARATOR_STR)),
|
||||
);
|
||||
|
||||
let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps"));
|
||||
let paths = [ui.as_path(), ui_fulldeps.as_path()];
|
||||
crate::walk::walk_no_read(&paths, |_, _| false, &mut |entry| {
|
||||
|
|
@ -100,6 +108,11 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
{
|
||||
tidy_error!(bad, "file {} has unexpected extension {}", file_path.display(), ext);
|
||||
}
|
||||
|
||||
// NB: We do not use file_stem() as some file names have multiple `.`s and we
|
||||
// must strip all of them.
|
||||
let testname =
|
||||
file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
|
||||
if ext == "stderr" || ext == "stdout" {
|
||||
// Test output filenames have one of the formats:
|
||||
// ```
|
||||
|
|
@ -111,12 +124,10 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
//
|
||||
// For now, just make sure that there is a corresponding
|
||||
// `$testname.rs` file.
|
||||
//
|
||||
// NB: We do not use file_stem() as some file names have multiple `.`s and we
|
||||
// must strip all of them.
|
||||
let testname =
|
||||
file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
|
||||
if !file_path.with_file_name(testname).with_extension("rs").exists() {
|
||||
|
||||
if !file_path.with_file_name(testname).with_extension("rs").exists()
|
||||
&& !testname.contains("ignore-tidy")
|
||||
{
|
||||
tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +137,38 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ext == "rs" {
|
||||
lazy_static! {
|
||||
static ref ISSUE_NAME_REGEX: Regex =
|
||||
Regex::new(r"^issues?[-_]?\d{3,}").unwrap();
|
||||
}
|
||||
|
||||
if ISSUE_NAME_REGEX.is_match(testname) {
|
||||
// these paths are always relative to the passed `path` and always UTF8
|
||||
let stripped_path = file_path.strip_prefix(path).unwrap().to_str().unwrap();
|
||||
if !allowed_issue_filenames.remove(stripped_path) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"UI test `{}` should use a name that describes the test and link the issue in a comment instead.",
|
||||
file_path.display(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if an excluded file is renamed, it must be removed from this list
|
||||
if allowed_issue_filenames.len() > 0 {
|
||||
for file_name in allowed_issue_filenames {
|
||||
let mut p = PathBuf::from(path);
|
||||
p.push(file_name);
|
||||
tidy_error!(
|
||||
bad,
|
||||
"file `{}` no longer exists and should be removed from the exclusions in `src/tools/tidy/src/issues.txt`",
|
||||
p.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue