mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 15:14:32 +00:00
Merge commit '99718d0c8bc5aadd993acdcabc1778fc7b5cc572' into sync-from-ra
This commit is contained in:
parent
4704881b64
commit
0155385b57
60 changed files with 714 additions and 402 deletions
15
.github/workflows/ci.yaml
vendored
15
.github/workflows/ci.yaml
vendored
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue