Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions crates/hir-ty/src/consteval/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,33 @@ fn cttz() {
"#,
3,
);
check_number(
r#"
#[rustc_intrinsic]
pub fn cttz<T: Copy>(x: T) -> T;

const GOAL: i8 = cttz(0i8);
"#,
8,
);
check_number(
r#"
#[rustc_intrinsic]
pub fn cttz<T: Copy>(x: T) -> T;

const GOAL: u32 = cttz(0u32);
"#,
32,
);
check_number(
r#"
#[rustc_intrinsic]
pub fn cttz<T: Copy>(x: T) -> T;

const GOAL: u64 = cttz(0u64);
"#,
64,
);
}

#[test]
Expand Down
4 changes: 3 additions & 1 deletion crates/hir-ty/src/mir/eval/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> {
let [arg] = args else {
return Err(MirEvalError::InternalError("cttz arg is not provided".into()));
};
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros();
let arg: &[u8] = arg.get(self)?;
let bit_count = arg.len() as u32 * 8;
let result = u128::from_le_bytes(pad16(arg, false)).trailing_zeros().min(bit_count);
destination
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
}
Expand Down
12 changes: 2 additions & 10 deletions crates/ide-completion/src/completions/postfix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ide_db::{
RootDatabase, SnippetCap,
documentation::{Documentation, HasDocs},
imports::insert_use::ImportScope,
source_change::SnippetEdit,
syntax_helpers::suggest_name::NameGenerator,
text_edit::TextEdit,
ty_filter::TryEnum,
Expand Down Expand Up @@ -401,7 +402,7 @@ fn get_receiver_text(

// The receiver texts should be interpreted as-is, as they are expected to be
// normal Rust expressions.
escape_snippet_bits(&mut text);
SnippetEdit::escape_snippet_bits(&mut text);
return text;

fn indent_of_tail_line(text: &str) -> usize {
Expand All @@ -411,15 +412,6 @@ fn get_receiver_text(
}
}

/// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs.
///
/// Note that we don't need to escape the other characters that can be escaped,
/// because they wouldn't be treated as snippet-specific constructs without '$'.
fn escape_snippet_bits(text: &mut String) {
stdx::replace(text, '\\', "\\\\");
stdx::replace(text, '$', "\\$");
}

fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr {
receiver
.syntax()
Expand Down
9 changes: 4 additions & 5 deletions crates/ide-completion/src/completions/postfix/format_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@

use ide_db::{
SnippetCap,
source_change::SnippetEdit,
syntax_helpers::format_string_exprs::{Arg, parse_format_exprs, with_placeholders},
};
use syntax::{AstToken, ast};

use crate::{
Completions,
completions::postfix::{build_postfix_snippet_builder, escape_snippet_bits},
context::CompletionContext,
Completions, completions::postfix::build_postfix_snippet_builder, context::CompletionContext,
};

/// Mapping ("postfix completion item" => "macro to use")
Expand Down Expand Up @@ -57,10 +56,10 @@ pub(crate) fn add_format_like_completions(

if let Ok((mut out, mut exprs)) = parse_format_exprs(receiver_text.text()) {
// Escape any snippet bits in the out text and any of the exprs.
escape_snippet_bits(&mut out);
SnippetEdit::escape_snippet_bits(&mut out);
for arg in &mut exprs {
if let Arg::Ident(text) | Arg::Expr(text) = arg {
escape_snippet_bits(text)
SnippetEdit::escape_snippet_bits(text)
}
}

Expand Down
9 changes: 9 additions & 0 deletions crates/ide-db/src/source_change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ impl SnippetEdit {
pub fn into_edit_ranges(self) -> Vec<(u32, TextRange)> {
self.0
}

/// Escapes `\` and `$` so that they don't get interpreted as snippet-specific constructs.
///
/// Note that we don't need to escape the other characters that can be escaped,
/// because they wouldn't be treated as snippet-specific constructs without '$'.
pub fn escape_snippet_bits(text: &mut String) {
stdx::replace(text, '\\', "\\\\");
stdx::replace(text, '$', "\\$");
}
}

pub struct SourceChangeBuilder {
Expand Down
23 changes: 21 additions & 2 deletions crates/ide/src/typing/on_enter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Handles the `Enter` key press, including comment continuation and
//! indentation in brace-delimited constructs.

use ide_db::{FilePosition, RootDatabase};
use ide_db::{FilePosition, RootDatabase, source_change::SnippetEdit};
use syntax::{
AstNode, SmolStr, SourceFile,
SyntaxKind::*,
Expand Down Expand Up @@ -113,7 +113,8 @@ fn on_enter_in_braces(l_curly: SyntaxToken, position: FilePosition) -> Option<Te
return None;
}

let (r_curly, content) = brace_contents_on_same_line(&l_curly)?;
let (r_curly, mut content) = brace_contents_on_same_line(&l_curly)?;
SnippetEdit::escape_snippet_bits(&mut content);
let indent = IndentLevel::from_token(&l_curly);
Some(TextEdit::replace(
TextRange::new(position.offset, r_curly.text_range().start()),
Expand Down Expand Up @@ -683,4 +684,22 @@ use path::{$0
"#,
);
}

#[test]
fn escapes_dollar_sign_in_brace_contents() {
do_check(
r#"
fn f() {
const {$0$bar};
}
"#,
r#"
fn f() {
const {
$0\$bar
};
}
"#,
);
}
}