Merge commit '99718d0c8bc5aadd993acdcabc1778fc7b5cc572' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-07-24 12:21:34 +03:00
parent 4704881b64
commit 0155385b57
60 changed files with 714 additions and 402 deletions

View file

@ -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'

View file

@ -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) => {

View file

@ -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>),

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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>>;

View file

@ -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);
}
}
}
}
}

View file

@ -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();

View file

@ -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);

View file

@ -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())

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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]

View file

@ -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,

View file

@ -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,

View file

@ -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(_, _) =
&current_ty.data(Interner).kind
&current_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 &current_ty.data(Interner).kind {
Ok(match &target_ty.kind(Interner) {
TyKind::Slice(_) => match &current_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 &current_ty.data(Interner).kind {
TyKind::Adt(id, target_subst) => match &current_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

View file

@ -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))
}

View file

@ -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))

View file

@ -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(

View file

@ -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
}
"#,
);
}

View file

@ -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, .. } => {

View file

@ -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()))
}
}

View file

@ -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; } }",
);
}
}

View file

@ -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
},
}
"#,
);
}
}

View file

@ -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())
}
}

View file

@ -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 })
}

View file

@ -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>
";

View file

@ -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 {

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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">&gt;&gt;</span> <span class="numeric_literal">1</span> <span class="bitwise">&lt;&lt;</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>

View file

@ -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>

View file

@ -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">&gt;</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">// =&gt; "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>

View file

@ -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">&gt;</span> <span class="brace">{</span>

View file

@ -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);

View file

@ -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<'_>) {

View file

@ -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]

View file

@ -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"

View file

@ -1,3 +0,0 @@
crate fn main() { }
struct S { crate field: u32 }
struct T(crate u32);

View file

@ -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"

View file

@ -1 +0,0 @@
fn foo() { crate::foo(); }

View file

@ -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()
}
}

View file

@ -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;
};

View file

@ -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"),

View file

@ -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,

View file

@ -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)),
}
}

View file

@ -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.

View file

@ -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"

View file

@ -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;
}