aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir_def/src/body/lower.rs10
-rw-r--r--crates/hir_def/src/expr.rs4
-rw-r--r--crates/hir_def/src/type_ref.rs73
-rw-r--r--crates/hir_ty/src/consteval.rs56
-rw-r--r--crates/hir_ty/src/consts.rs21
-rw-r--r--crates/hir_ty/src/display.rs5
-rw-r--r--crates/hir_ty/src/infer/expr.rs32
-rw-r--r--crates/hir_ty/src/interner.rs3
-rw-r--r--crates/hir_ty/src/lib.rs10
-rw-r--r--crates/hir_ty/src/lower.rs11
-rw-r--r--crates/hir_ty/src/tests/coercion.rs46
-rw-r--r--crates/hir_ty/src/tests/patterns.rs8
-rw-r--r--crates/hir_ty/src/tests/simple.rs65
-rw-r--r--crates/hir_ty/src/tests/traits.rs97
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--crates/ide_assists/src/handlers/add_explicit_type.rs28
-rw-r--r--crates/ide_assists/src/handlers/raw_string.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_string_with_char.rs2
-rw-r--r--crates/syntax/src/ast/token_ext.rs81
21 files changed, 427 insertions, 136 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 6233bca83..d443b124c 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -52,7 +52,9 @@ use hir_def::{
52}; 52};
53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
54use hir_ty::{ 54use hir_ty::{
55 autoderef, could_unify, 55 autoderef,
56 consteval::ConstExt,
57 could_unify,
56 method_resolution::{self, def_crates, TyFingerprint}, 58 method_resolution::{self, def_crates, TyFingerprint},
57 primitive::UintTy, 59 primitive::UintTy,
58 subst_prefix, 60 subst_prefix,
@@ -1914,6 +1916,7 @@ impl Type {
1914 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go) 1916 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
1915 } 1917 }
1916 1918
1919 TyKind::Array(_ty, len) if len.is_unknown() => true,
1917 TyKind::Array(ty, _) 1920 TyKind::Array(ty, _)
1918 | TyKind::Slice(ty) 1921 | TyKind::Slice(ty)
1919 | TyKind::Raw(_, ty) 1922 | TyKind::Raw(_, ty)
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 9f278d35b..2a7e0205f 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1006,23 +1006,27 @@ impl From<ast::BinOp> for BinaryOp {
1006impl From<ast::LiteralKind> for Literal { 1006impl From<ast::LiteralKind> for Literal {
1007 fn from(ast_lit_kind: ast::LiteralKind) -> Self { 1007 fn from(ast_lit_kind: ast::LiteralKind) -> Self {
1008 match ast_lit_kind { 1008 match ast_lit_kind {
1009 // FIXME: these should have actual values filled in, but unsure on perf impact
1009 LiteralKind::IntNumber(lit) => { 1010 LiteralKind::IntNumber(lit) => {
1010 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { 1011 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
1011 return Literal::Float(Default::default(), builtin); 1012 return Literal::Float(Default::default(), builtin);
1012 } else if let builtin @ Some(_) = 1013 } else if let builtin @ Some(_) =
1013 lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it)) 1014 lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it))
1014 { 1015 {
1015 Literal::Int(Default::default(), builtin) 1016 Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1016 } else { 1017 } else {
1017 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it)); 1018 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it));
1018 Literal::Uint(Default::default(), builtin) 1019 Literal::Uint(lit.value().unwrap_or(0), builtin)
1019 } 1020 }
1020 } 1021 }
1021 LiteralKind::FloatNumber(lit) => { 1022 LiteralKind::FloatNumber(lit) => {
1022 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); 1023 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
1023 Literal::Float(Default::default(), ty) 1024 Literal::Float(Default::default(), ty)
1024 } 1025 }
1025 LiteralKind::ByteString(_) => Literal::ByteString(Default::default()), 1026 LiteralKind::ByteString(bs) => {
1027 let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
1028 Literal::ByteString(text)
1029 }
1026 LiteralKind::String(_) => Literal::String(Default::default()), 1030 LiteralKind::String(_) => Literal::String(Default::default()),
1027 LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)), 1031 LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
1028 LiteralKind::Bool(val) => Literal::Bool(val), 1032 LiteralKind::Bool(val) => Literal::Bool(val),
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 0c3b41080..2ba619d23 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -43,8 +43,8 @@ pub enum Literal {
43 ByteString(Vec<u8>), 43 ByteString(Vec<u8>),
44 Char(char), 44 Char(char),
45 Bool(bool), 45 Bool(bool),
46 Int(u64, Option<BuiltinInt>), 46 Int(i128, Option<BuiltinInt>),
47 Uint(u64, Option<BuiltinUint>), 47 Uint(u128, Option<BuiltinUint>),
48 Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq 48 Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq
49} 49}
50 50
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index ea29da5da..9e44547cb 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -2,6 +2,7 @@
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3 3
4use hir_expand::{name::Name, AstId, InFile}; 4use hir_expand::{name::Name, AstId, InFile};
5use std::convert::TryInto;
5use syntax::ast; 6use syntax::ast;
6 7
7use crate::{body::LowerCtx, path::Path}; 8use crate::{body::LowerCtx, path::Path};
@@ -79,7 +80,9 @@ pub enum TypeRef {
79 Path(Path), 80 Path(Path),
80 RawPtr(Box<TypeRef>, Mutability), 81 RawPtr(Box<TypeRef>, Mutability),
81 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), 82 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
82 Array(Box<TypeRef> /*, Expr*/), 83 // FIXME: for full const generics, the latter element (length) here is going to have to be an
84 // expression that is further lowered later in hir_ty.
85 Array(Box<TypeRef>, ConstScalar),
83 Slice(Box<TypeRef>), 86 Slice(Box<TypeRef>),
84 /// A fn pointer. Last element of the vector is the return type. 87 /// A fn pointer. Last element of the vector is the return type.
85 Fn(Vec<TypeRef>, bool /*varargs*/), 88 Fn(Vec<TypeRef>, bool /*varargs*/),
@@ -140,7 +143,16 @@ impl TypeRef {
140 TypeRef::RawPtr(Box::new(inner_ty), mutability) 143 TypeRef::RawPtr(Box::new(inner_ty), mutability)
141 } 144 }
142 ast::Type::ArrayType(inner) => { 145 ast::Type::ArrayType(inner) => {
143 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 146 // FIXME: This is a hack. We should probably reuse the machinery of
147 // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
148 // `hir_ty` level, which would allow knowing the type of:
149 // let v: [u8; 2 + 2] = [0u8; 4];
150 let len = inner
151 .expr()
152 .map(ConstScalar::usize_from_literal_expr)
153 .unwrap_or(ConstScalar::Unknown);
154
155 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len)
144 } 156 }
145 ast::Type::SliceType(inner) => { 157 ast::Type::SliceType(inner) => {
146 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 158 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
@@ -212,7 +224,7 @@ impl TypeRef {
212 } 224 }
213 TypeRef::RawPtr(type_ref, _) 225 TypeRef::RawPtr(type_ref, _)
214 | TypeRef::Reference(type_ref, ..) 226 | TypeRef::Reference(type_ref, ..)
215 | TypeRef::Array(type_ref) 227 | TypeRef::Array(type_ref, _)
216 | TypeRef::Slice(type_ref) => go(&type_ref, f), 228 | TypeRef::Slice(type_ref) => go(&type_ref, f),
217 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 229 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
218 for bound in bounds { 230 for bound in bounds {
@@ -298,3 +310,58 @@ impl TypeBound {
298 } 310 }
299 } 311 }
300} 312}
313
314/// A concrete constant value
315#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
316pub enum ConstScalar {
317 // for now, we only support the trivial case of constant evaluating the length of an array
318 // Note that this is u64 because the target usize may be bigger than our usize
319 Usize(u64),
320
321 /// Case of an unknown value that rustc might know but we don't
322 // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
323 // constants
324 // https://github.com/rust-analyzer/rust-analyzer/pull/8813#issuecomment-840679177
325 // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
326 Unknown,
327}
328
329impl std::fmt::Display for ConstScalar {
330 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
331 match self {
332 ConstScalar::Usize(us) => write!(fmt, "{}", us),
333 ConstScalar::Unknown => write!(fmt, "_"),
334 }
335 }
336}
337
338impl ConstScalar {
339 /// Gets a target usize out of the ConstScalar
340 pub fn as_usize(&self) -> Option<u64> {
341 match self {
342 &ConstScalar::Usize(us) => Some(us),
343 _ => None,
344 }
345 }
346
347 // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
348 // parse stage.
349 fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
350 match expr {
351 ast::Expr::Literal(lit) => {
352 let lkind = lit.kind();
353 match lkind {
354 ast::LiteralKind::IntNumber(num)
355 if num.suffix() == None || num.suffix() == Some("usize") =>
356 {
357 num.value().and_then(|v| v.try_into().ok())
358 }
359 _ => None,
360 }
361 }
362 _ => None,
363 }
364 .map(ConstScalar::Usize)
365 .unwrap_or(ConstScalar::Unknown)
366 }
367}
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs
new file mode 100644
index 000000000..e3ceb3d62
--- /dev/null
+++ b/crates/hir_ty/src/consteval.rs
@@ -0,0 +1,56 @@
1//! Constant evaluation details
2
3use std::convert::TryInto;
4
5use hir_def::{
6 builtin_type::BuiltinUint,
7 expr::{Expr, Literal},
8 type_ref::ConstScalar,
9};
10
11use crate::{Const, ConstData, ConstValue, Interner, TyKind};
12
13/// Extension trait for [`Const`]
14pub trait ConstExt {
15 /// Is a [`Const`] unknown?
16 fn is_unknown(&self) -> bool;
17}
18
19impl ConstExt for Const {
20 fn is_unknown(&self) -> bool {
21 match self.data(&Interner).value {
22 // interned Unknown
23 chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
24 interned: ConstScalar::Unknown,
25 }) => true,
26
27 // interned concrete anything else
28 chalk_ir::ConstValue::Concrete(..) => false,
29
30 _ => {
31 log::error!("is_unknown was called on a non-concrete constant value! {:?}", self);
32 true
33 }
34 }
35 }
36}
37
38// FIXME: support more than just evaluating literals
39pub fn eval_usize(expr: &Expr) -> Option<u64> {
40 match expr {
41 Expr::Literal(Literal::Uint(v, None))
42 | Expr::Literal(Literal::Uint(v, Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
43 _ => None,
44 }
45}
46
47/// Interns a possibly-unknown target usize
48pub fn usize_const(value: Option<u64>) -> Const {
49 ConstData {
50 ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(&Interner),
51 value: ConstValue::Concrete(chalk_ir::ConcreteConst {
52 interned: value.map(|value| ConstScalar::Usize(value)).unwrap_or(ConstScalar::Unknown),
53 }),
54 }
55 .intern(&Interner)
56}
diff --git a/crates/hir_ty/src/consts.rs b/crates/hir_ty/src/consts.rs
deleted file mode 100644
index 0044b1cff..000000000
--- a/crates/hir_ty/src/consts.rs
+++ /dev/null
@@ -1,21 +0,0 @@
1//! Handling of concrete const values
2
3/// A concrete constant value
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum ConstScalar {
6 // for now, we only support the trivial case of constant evaluating the length of an array
7 // Note that this is u64 because the target usize may be bigger than our usize
8 Usize(u64),
9
10 /// Case of an unknown value that rustc might know but we don't
11 Unknown,
12}
13
14impl std::fmt::Display for ConstScalar {
15 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
16 match self {
17 ConstScalar::Usize(us) => write!(fmt, "{}", us),
18 ConstScalar::Unknown => write!(fmt, "_"),
19 }
20 }
21}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 8a4296697..7bbd1a1f7 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -962,11 +962,10 @@ impl HirDisplay for TypeRef {
962 write!(f, "{}", mutability)?; 962 write!(f, "{}", mutability)?;
963 inner.hir_fmt(f)?; 963 inner.hir_fmt(f)?;
964 } 964 }
965 TypeRef::Array(inner) => { 965 TypeRef::Array(inner, len) => {
966 write!(f, "[")?; 966 write!(f, "[")?;
967 inner.hir_fmt(f)?; 967 inner.hir_fmt(f)?;
968 // FIXME: Array length? 968 write!(f, "; {}]", len)?;
969 write!(f, "; _]")?;
970 } 969 }
971 TypeRef::Slice(inner) => { 970 TypeRef::Slice(inner) => {
972 write!(f, "[")?; 971 write!(f, "[")?;
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 2178ffd07..b6b5a1b75 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{cast::Cast, fold::Shift, ConstData, Mutability, TyVariableKind}; 6use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
7use hir_def::{ 7use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
@@ -15,9 +15,7 @@ use stdx::always;
15use syntax::ast::RangeOp; 15use syntax::ast::RangeOp;
16 16
17use crate::{ 17use crate::{
18 autoderef, 18 autoderef, consteval,
19 consts::ConstScalar,
20 dummy_usize_const,
21 lower::lower_to_chalk_mutability, 19 lower::lower_to_chalk_mutability,
22 mapping::from_chalk, 20 mapping::from_chalk,
23 method_resolution, op, 21 method_resolution, op,
@@ -25,7 +23,7 @@ use crate::{
25 static_lifetime, to_chalk_trait_id, 23 static_lifetime, to_chalk_trait_id,
26 traits::FnTrait, 24 traits::FnTrait,
27 utils::{generics, Generics}, 25 utils::{generics, Generics},
28 AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 26 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
29 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, 27 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
30}; 28};
31 29
@@ -724,7 +722,7 @@ impl<'a> InferenceContext<'a> {
724 for expr in items.iter() { 722 for expr in items.iter() {
725 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); 723 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
726 } 724 }
727 Some(items.len()) 725 Some(items.len() as u64)
728 } 726 }
729 Array::Repeat { initializer, repeat } => { 727 Array::Repeat { initializer, repeat } => {
730 self.infer_expr_coerce( 728 self.infer_expr_coerce(
@@ -737,20 +735,13 @@ impl<'a> InferenceContext<'a> {
737 TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner), 735 TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
738 ), 736 ),
739 ); 737 );
740 // FIXME: support length for Repeat array expressions 738
741 None 739 let repeat_expr = &self.body.exprs[*repeat];
740 consteval::eval_usize(repeat_expr)
742 } 741 }
743 }; 742 };
744 743
745 let cd = ConstData { 744 TyKind::Array(elem_ty, consteval::usize_const(len)).intern(&Interner)
746 ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
747 value: ConstValue::Concrete(chalk_ir::ConcreteConst {
748 interned: len
749 .map(|len| ConstScalar::Usize(len as u64))
750 .unwrap_or(ConstScalar::Unknown),
751 }),
752 };
753 TyKind::Array(elem_ty, cd.intern(&Interner)).intern(&Interner)
754 } 745 }
755 Expr::Literal(lit) => match lit { 746 Expr::Literal(lit) => match lit {
756 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 747 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
@@ -758,11 +749,12 @@ impl<'a> InferenceContext<'a> {
758 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner)) 749 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
759 .intern(&Interner) 750 .intern(&Interner)
760 } 751 }
761 Literal::ByteString(..) => { 752 Literal::ByteString(bs) => {
762 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 753 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
763 754
764 let array_type = 755 let len = consteval::usize_const(Some(bs.len() as u64));
765 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner); 756
757 let array_type = TyKind::Array(byte_type, len).intern(&Interner);
766 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner) 758 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
767 } 759 }
768 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner), 760 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
diff --git a/crates/hir_ty/src/interner.rs b/crates/hir_ty/src/interner.rs
index 4cbc9cd4f..7b4119747 100644
--- a/crates/hir_ty/src/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -1,11 +1,12 @@
1//! Implementation of the Chalk `Interner` trait, which allows customizing the 1//! Implementation of the Chalk `Interner` trait, which allows customizing the
2//! representation of the various objects Chalk deals with (types, goals etc.). 2//! representation of the various objects Chalk deals with (types, goals etc.).
3 3
4use crate::{chalk_db, consts::ConstScalar, tls, GenericArg}; 4use crate::{chalk_db, tls, GenericArg};
5use base_db::salsa::InternId; 5use base_db::salsa::InternId;
6use chalk_ir::{Goal, GoalData}; 6use chalk_ir::{Goal, GoalData};
7use hir_def::{ 7use hir_def::{
8 intern::{impl_internable, InternStorage, Internable, Interned}, 8 intern::{impl_internable, InternStorage, Internable, Interned},
9 type_ref::ConstScalar,
9 TypeAliasId, 10 TypeAliasId,
10}; 11};
11use smallvec::SmallVec; 12use smallvec::SmallVec;
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index d23eff513..15b61bedc 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -10,9 +10,9 @@ mod autoderef;
10mod builder; 10mod builder;
11mod chalk_db; 11mod chalk_db;
12mod chalk_ext; 12mod chalk_ext;
13pub mod consteval;
13mod infer; 14mod infer;
14mod interner; 15mod interner;
15mod consts;
16mod lower; 16mod lower;
17mod mapping; 17mod mapping;
18mod op; 18mod op;
@@ -38,9 +38,13 @@ use chalk_ir::{
38 interner::HasInterner, 38 interner::HasInterner,
39 UintTy, 39 UintTy,
40}; 40};
41use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId}; 41use hir_def::{
42 expr::ExprId,
43 type_ref::{ConstScalar, Rawness},
44 TypeParamId,
45};
42 46
43use crate::{consts::ConstScalar, db::HirDatabase, display::HirDisplay, utils::generics}; 47use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
44 48
45pub use autoderef::autoderef; 49pub use autoderef::autoderef;
46pub use builder::TyBuilder; 50pub use builder::TyBuilder;
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 9751b45e4..bd8bb6028 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -29,8 +29,8 @@ use stdx::impl_from;
29use syntax::ast; 29use syntax::ast;
30 30
31use crate::{ 31use crate::{
32 consteval,
32 db::HirDatabase, 33 db::HirDatabase,
33 dummy_usize_const,
34 mapping::ToChalk, 34 mapping::ToChalk,
35 static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, 35 static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
36 utils::{ 36 utils::{
@@ -172,11 +172,12 @@ impl<'a> TyLoweringContext<'a> {
172 let inner_ty = self.lower_ty(inner); 172 let inner_ty = self.lower_ty(inner);
173 TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner) 173 TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner)
174 } 174 }
175 TypeRef::Array(inner) => { 175 TypeRef::Array(inner, len) => {
176 let inner_ty = self.lower_ty(inner); 176 let inner_ty = self.lower_ty(inner);
177 // FIXME: we don't have length info here because we don't store an expression for 177
178 // the length 178 let const_len = consteval::usize_const(len.as_usize());
179 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner) 179
180 TyKind::Array(inner_ty, const_len).intern(&Interner)
180 } 181 }
181 TypeRef::Slice(inner) => { 182 TypeRef::Slice(inner) => {
182 let inner_ty = self.lower_ty(inner); 183 let inner_ty = self.lower_ty(inner);
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index aad3d610e..190471069 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -64,42 +64,42 @@ fn coerce_places() {
64 81..92 '{ loop {} }': T 64 81..92 '{ loop {} }': T
65 83..90 'loop {}': ! 65 83..90 'loop {}': !
66 88..90 '{}': () 66 88..90 '{}': ()
67 121..132 '{ loop {} }': *mut [T; _] 67 121..132 '{ loop {} }': *mut [T; 2]
68 123..130 'loop {}': ! 68 123..130 'loop {}': !
69 128..130 '{}': () 69 128..130 '{}': ()
70 159..172 '{ gen() }': *mut [U] 70 159..172 '{ gen() }': *mut [U]
71 165..168 'gen': fn gen<U>() -> *mut [U; _] 71 165..168 'gen': fn gen<U>() -> *mut [U; 2]
72 165..170 'gen()': *mut [U; _] 72 165..170 'gen()': *mut [U; 2]
73 185..419 '{ ...rr); }': () 73 185..419 '{ ...rr); }': ()
74 195..198 'arr': &[u8; _] 74 195..198 'arr': &[u8; 1]
75 211..215 '&[1]': &[u8; 1] 75 211..215 '&[1]': &[u8; 1]
76 212..215 '[1]': [u8; 1] 76 212..215 '[1]': [u8; 1]
77 213..214 '1': u8 77 213..214 '1': u8
78 226..227 'a': &[u8] 78 226..227 'a': &[u8]
79 236..239 'arr': &[u8; _] 79 236..239 'arr': &[u8; 1]
80 249..250 'b': u8 80 249..250 'b': u8
81 253..254 'f': fn f<u8>(&[u8]) -> u8 81 253..254 'f': fn f<u8>(&[u8]) -> u8
82 253..259 'f(arr)': u8 82 253..259 'f(arr)': u8
83 255..258 'arr': &[u8; _] 83 255..258 'arr': &[u8; 1]
84 269..270 'c': &[u8] 84 269..270 'c': &[u8]
85 279..286 '{ arr }': &[u8] 85 279..286 '{ arr }': &[u8]
86 281..284 'arr': &[u8; _] 86 281..284 'arr': &[u8; 1]
87 296..297 'd': u8 87 296..297 'd': u8
88 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 88 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
89 300..315 'g(S { a: arr })': u8 89 300..315 'g(S { a: arr })': u8
90 302..314 'S { a: arr }': S<&[u8]> 90 302..314 'S { a: arr }': S<&[u8]>
91 309..312 'arr': &[u8; _] 91 309..312 'arr': &[u8; 1]
92 325..326 'e': [&[u8]; _] 92 325..326 'e': [&[u8]; 1]
93 340..345 '[arr]': [&[u8]; 1] 93 340..345 '[arr]': [&[u8]; 1]
94 341..344 'arr': &[u8; _] 94 341..344 'arr': &[u8; 1]
95 355..356 'f': [&[u8]; _] 95 355..356 'f': [&[u8]; 2]
96 370..378 '[arr; 2]': [&[u8]; _] 96 370..378 '[arr; 2]': [&[u8]; 2]
97 371..374 'arr': &[u8; _] 97 371..374 'arr': &[u8; 1]
98 376..377 '2': usize 98 376..377 '2': usize
99 388..389 'g': (&[u8], &[u8]) 99 388..389 'g': (&[u8], &[u8])
100 406..416 '(arr, arr)': (&[u8], &[u8]) 100 406..416 '(arr, arr)': (&[u8], &[u8])
101 407..410 'arr': &[u8; _] 101 407..410 'arr': &[u8; 1]
102 412..415 'arr': &[u8; _] 102 412..415 'arr': &[u8; 1]
103 "#]], 103 "#]],
104 ); 104 );
105} 105}
@@ -159,7 +159,7 @@ fn infer_custom_coerce_unsized() {
159 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 159 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
160 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 160 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
161 "#, 161 "#,
162 expect![[r" 162 expect![[r#"
163 257..258 'x': A<[T]> 163 257..258 'x': A<[T]>
164 278..283 '{ x }': A<[T]> 164 278..283 '{ x }': A<[T]>
165 280..281 'x': A<[T]> 165 280..281 'x': A<[T]>
@@ -169,23 +169,23 @@ fn infer_custom_coerce_unsized() {
169 333..334 'x': C<[T]> 169 333..334 'x': C<[T]>
170 354..359 '{ x }': C<[T]> 170 354..359 '{ x }': C<[T]>
171 356..357 'x': C<[T]> 171 356..357 'x': C<[T]>
172 369..370 'a': A<[u8; _]> 172 369..370 'a': A<[u8; 2]>
173 384..385 'b': B<[u8; _]> 173 384..385 'b': B<[u8; 2]>
174 399..400 'c': C<[u8; _]> 174 399..400 'c': C<[u8; 2]>
175 414..480 '{ ...(c); }': () 175 414..480 '{ ...(c); }': ()
176 424..425 'd': A<[{unknown}]> 176 424..425 'd': A<[{unknown}]>
177 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 177 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
178 428..435 'foo1(a)': A<[{unknown}]> 178 428..435 'foo1(a)': A<[{unknown}]>
179 433..434 'a': A<[u8; _]> 179 433..434 'a': A<[u8; 2]>
180 445..446 'e': B<[u8]> 180 445..446 'e': B<[u8]>
181 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> 181 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
182 449..456 'foo2(b)': B<[u8]> 182 449..456 'foo2(b)': B<[u8]>
183 454..455 'b': B<[u8; _]> 183 454..455 'b': B<[u8; 2]>
184 466..467 'f': C<[u8]> 184 466..467 'f': C<[u8]>
185 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> 185 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
186 470..477 'foo3(c)': C<[u8]> 186 470..477 'foo3(c)': C<[u8]>
187 475..476 'c': C<[u8; _]> 187 475..476 'c': C<[u8; 2]>
188 "]], 188 "#]],
189 ); 189 );
190} 190}
191 191
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index a0a7b4d0b..787647e9f 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -345,19 +345,19 @@ fn infer_pattern_match_arr() {
345 "#, 345 "#,
346 expect![[r#" 346 expect![[r#"
347 10..179 '{ ... } }': () 347 10..179 '{ ... } }': ()
348 20..23 'arr': [f64; _] 348 20..23 'arr': [f64; 2]
349 36..46 '[0.0, 1.0]': [f64; 2] 349 36..46 '[0.0, 1.0]': [f64; 2]
350 37..40 '0.0': f64 350 37..40 '0.0': f64
351 42..45 '1.0': f64 351 42..45 '1.0': f64
352 52..177 'match ... }': () 352 52..177 'match ... }': ()
353 58..61 'arr': [f64; _] 353 58..61 'arr': [f64; 2]
354 72..80 '[1.0, a]': [f64; _] 354 72..80 '[1.0, a]': [f64; 2]
355 73..76 '1.0': f64 355 73..76 '1.0': f64
356 73..76 '1.0': f64 356 73..76 '1.0': f64
357 78..79 'a': f64 357 78..79 'a': f64
358 84..110 '{ ... }': () 358 84..110 '{ ... }': ()
359 98..99 'a': f64 359 98..99 'a': f64
360 120..126 '[b, c]': [f64; _] 360 120..126 '[b, c]': [f64; 2]
361 121..122 'b': f64 361 121..122 'b': f64
362 124..125 'c': f64 362 124..125 'c': f64
363 130..171 '{ ... }': () 363 130..171 '{ ... }': ()
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 8b09f2e4a..a9cd42186 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -488,23 +488,34 @@ fn infer_literals() {
488 mod foo {} 488 mod foo {}
489 "#; 489 "#;
490 br#"yolo"#; 490 br#"yolo"#;
491 let a = b"a\x20b\
492 c";
493 let b = br"g\
494h";
495 let c = br#"x"\"yb"#;
491 } 496 }
492 "##, 497 "##,
493 expect![[r##" 498 expect![[r##"
494 10..216 '{ ...o"#; }': () 499 18..478 '{ ... }': ()
495 16..20 '5i32': i32 500 32..36 '5i32': i32
496 26..30 '5f32': f32 501 50..54 '5f32': f32
497 36..40 '5f64': f64 502 68..72 '5f64': f64
498 46..53 '"hello"': &str 503 86..93 '"hello"': &str
499 59..67 'b"bytes"': &[u8; _] 504 107..115 'b"bytes"': &[u8; 5]
500 73..76 ''c'': char 505 129..132 ''c'': char
501 82..86 'b'b'': u8 506 146..150 'b'b'': u8
502 92..96 '3.14': f64 507 164..168 '3.14': f64
503 102..106 '5000': i32 508 182..186 '5000': i32
504 112..117 'false': bool 509 200..205 'false': bool
505 123..127 'true': bool 510 219..223 'true': bool
506 133..197 'r#" ... "#': &str 511 237..333 'r#" ... "#': &str
507 203..213 'br#"yolo"#': &[u8; _] 512 347..357 'br#"yolo"#': &[u8; 4]
513 375..376 'a': &[u8; 4]
514 379..403 'b"a\x2... c"': &[u8; 4]
515 421..422 'b': &[u8; 4]
516 425..433 'br"g\ h"': &[u8; 4]
517 451..452 'c': &[u8; 6]
518 455..467 'br#"x"\"yb"#': &[u8; 6]
508 "##]], 519 "##]],
509 ); 520 );
510} 521}
@@ -1260,12 +1271,14 @@ fn infer_array() {
1260 1271
1261 let b = [a, ["b"]]; 1272 let b = [a, ["b"]];
1262 let x: [u8; 0] = []; 1273 let x: [u8; 0] = [];
1274 // FIXME: requires const evaluation/taking type from rhs somehow
1275 let y: [u8; 2+2] = [1,2,3,4];
1263 } 1276 }
1264 "#, 1277 "#,
1265 expect![[r#" 1278 expect![[r#"
1266 8..9 'x': &str 1279 8..9 'x': &str
1267 17..18 'y': isize 1280 17..18 'y': isize
1268 27..292 '{ ... []; }': () 1281 27..395 '{ ...,4]; }': ()
1269 37..38 'a': [&str; 1] 1282 37..38 'a': [&str; 1]
1270 41..44 '[x]': [&str; 1] 1283 41..44 '[x]': [&str; 1]
1271 42..43 'x': &str 1284 42..43 'x': &str
@@ -1313,8 +1326,14 @@ fn infer_array() {
1313 255..256 'a': [&str; 1] 1326 255..256 'a': [&str; 1]
1314 258..263 '["b"]': [&str; 1] 1327 258..263 '["b"]': [&str; 1]
1315 259..262 '"b"': &str 1328 259..262 '"b"': &str
1316 274..275 'x': [u8; _] 1329 274..275 'x': [u8; 0]
1317 287..289 '[]': [u8; 0] 1330 287..289 '[]': [u8; 0]
1331 368..369 'y': [u8; _]
1332 383..392 '[1,2,3,4]': [u8; 4]
1333 384..385 '1': u8
1334 386..387 '2': u8
1335 388..389 '3': u8
1336 390..391 '4': u8
1318 "#]], 1337 "#]],
1319 ); 1338 );
1320} 1339}
@@ -2409,38 +2428,38 @@ fn infer_operator_overload() {
2409 320..422 '{ ... }': V2 2428 320..422 '{ ... }': V2
2410 334..335 'x': f32 2429 334..335 'x': f32
2411 338..342 'self': V2 2430 338..342 'self': V2
2412 338..344 'self.0': [f32; _] 2431 338..344 'self.0': [f32; 2]
2413 338..347 'self.0[0]': {unknown} 2432 338..347 'self.0[0]': {unknown}
2414 338..358 'self.0...s.0[0]': f32 2433 338..358 'self.0...s.0[0]': f32
2415 345..346 '0': i32 2434 345..346 '0': i32
2416 350..353 'rhs': V2 2435 350..353 'rhs': V2
2417 350..355 'rhs.0': [f32; _] 2436 350..355 'rhs.0': [f32; 2]
2418 350..358 'rhs.0[0]': {unknown} 2437 350..358 'rhs.0[0]': {unknown}
2419 356..357 '0': i32 2438 356..357 '0': i32
2420 372..373 'y': f32 2439 372..373 'y': f32
2421 376..380 'self': V2 2440 376..380 'self': V2
2422 376..382 'self.0': [f32; _] 2441 376..382 'self.0': [f32; 2]
2423 376..385 'self.0[1]': {unknown} 2442 376..385 'self.0[1]': {unknown}
2424 376..396 'self.0...s.0[1]': f32 2443 376..396 'self.0...s.0[1]': f32
2425 383..384 '1': i32 2444 383..384 '1': i32
2426 388..391 'rhs': V2 2445 388..391 'rhs': V2
2427 388..393 'rhs.0': [f32; _] 2446 388..393 'rhs.0': [f32; 2]
2428 388..396 'rhs.0[1]': {unknown} 2447 388..396 'rhs.0[1]': {unknown}
2429 394..395 '1': i32 2448 394..395 '1': i32
2430 406..408 'V2': V2([f32; _]) -> V2 2449 406..408 'V2': V2([f32; 2]) -> V2
2431 406..416 'V2([x, y])': V2 2450 406..416 'V2([x, y])': V2
2432 409..415 '[x, y]': [f32; 2] 2451 409..415 '[x, y]': [f32; 2]
2433 410..411 'x': f32 2452 410..411 'x': f32
2434 413..414 'y': f32 2453 413..414 'y': f32
2435 436..519 '{ ... vb; }': () 2454 436..519 '{ ... vb; }': ()
2436 446..448 'va': V2 2455 446..448 'va': V2
2437 451..453 'V2': V2([f32; _]) -> V2 2456 451..453 'V2': V2([f32; 2]) -> V2
2438 451..465 'V2([0.0, 1.0])': V2 2457 451..465 'V2([0.0, 1.0])': V2
2439 454..464 '[0.0, 1.0]': [f32; 2] 2458 454..464 '[0.0, 1.0]': [f32; 2]
2440 455..458 '0.0': f32 2459 455..458 '0.0': f32
2441 460..463 '1.0': f32 2460 460..463 '1.0': f32
2442 475..477 'vb': V2 2461 475..477 'vb': V2
2443 480..482 'V2': V2([f32; _]) -> V2 2462 480..482 'V2': V2([f32; 2]) -> V2
2444 480..494 'V2([0.0, 1.0])': V2 2463 480..494 'V2([0.0, 1.0])': V2
2445 483..493 '[0.0, 1.0]': [f32; 2] 2464 483..493 '[0.0, 1.0]': [f32; 2]
2446 484..487 '0.0': f32 2465 484..487 '0.0': f32
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 47a1455fd..f80cf9879 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3474,3 +3474,100 @@ fn main(){
3474 "#]], 3474 "#]],
3475 ) 3475 )
3476} 3476}
3477
3478#[test]
3479fn array_length() {
3480 check_infer(
3481 r#"
3482trait T {
3483 type Output;
3484 fn do_thing(&self) -> Self::Output;
3485}
3486
3487impl T for [u8; 4] {
3488 type Output = usize;
3489 fn do_thing(&self) -> Self::Output {
3490 2
3491 }
3492}
3493
3494impl T for [u8; 2] {
3495 type Output = u8;
3496 fn do_thing(&self) -> Self::Output {
3497 2
3498 }
3499}
3500
3501fn main() {
3502 let v = [0u8; 2];
3503 let v2 = v.do_thing();
3504 let v3 = [0u8; 4];
3505 let v4 = v3.do_thing();
3506}
3507"#,
3508 expect![[r#"
3509 44..48 'self': &Self
3510 133..137 'self': &[u8; 4]
3511 155..172 '{ ... }': usize
3512 165..166 '2': usize
3513 236..240 'self': &[u8; 2]
3514 258..275 '{ ... }': u8
3515 268..269 '2': u8
3516 289..392 '{ ...g(); }': ()
3517 299..300 'v': [u8; 2]
3518 303..311 '[0u8; 2]': [u8; 2]
3519 304..307 '0u8': u8
3520 309..310 '2': usize
3521 321..323 'v2': u8
3522 326..327 'v': [u8; 2]
3523 326..338 'v.do_thing()': u8
3524 348..350 'v3': [u8; 4]
3525 353..361 '[0u8; 4]': [u8; 4]
3526 354..357 '0u8': u8
3527 359..360 '4': usize
3528 371..373 'v4': usize
3529 376..378 'v3': [u8; 4]
3530 376..389 'v3.do_thing()': usize
3531 "#]],
3532 )
3533}
3534
3535// FIXME: We should infer the length of the returned array :)
3536#[test]
3537fn const_generics() {
3538 check_infer(
3539 r#"
3540trait T {
3541 type Output;
3542 fn do_thing(&self) -> Self::Output;
3543}
3544
3545impl<const L: usize> T for [u8; L] {
3546 type Output = [u8; L];
3547 fn do_thing(&self) -> Self::Output {
3548 *self
3549 }
3550}
3551
3552fn main() {
3553 let v = [0u8; 2];
3554 let v2 = v.do_thing();
3555}
3556"#,
3557 expect![[r#"
3558 44..48 'self': &Self
3559 151..155 'self': &[u8; _]
3560 173..194 '{ ... }': [u8; _]
3561 183..188 '*self': [u8; _]
3562 184..188 'self': &[u8; _]
3563 208..260 '{ ...g(); }': ()
3564 218..219 'v': [u8; 2]
3565 222..230 '[0u8; 2]': [u8; 2]
3566 223..226 '0u8': u8
3567 228..229 '2': usize
3568 240..242 'v2': [u8; _]
3569 245..246 'v': [u8; 2]
3570 245..257 'v.do_thing()': [u8; _]
3571 "#]],
3572 )
3573}
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 61dcbb399..c67ccd1a9 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -4,7 +4,7 @@ use ide_assists::utils::extract_trivial_expression;
4use itertools::Itertools; 4use itertools::Itertools;
5use syntax::{ 5use syntax::{
6 algo::non_trivia_sibling, 6 algo::non_trivia_sibling,
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken, IsString},
8 Direction, NodeOrToken, SourceFile, 8 Direction, NodeOrToken, SourceFile,
9 SyntaxKind::{self, USE_TREE, WHITESPACE}, 9 SyntaxKind::{self, USE_TREE, WHITESPACE},
10 SyntaxNode, SyntaxToken, TextRange, TextSize, T, 10 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index bc221d599..4269d339e 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -6,7 +6,7 @@ use either::Either;
6use hir::{InFile, Semantics}; 6use hir::{InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind}; 7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode}, 9 ast::{self, AstNode, IsString},
10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12 12
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 62db31952..36589203d 100644
--- a/crates/ide_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide_assists/src/handlers/add_explicit_type.rs
@@ -198,6 +198,34 @@ fn main() {
198 ) 198 )
199 } 199 }
200 200
201 /// https://github.com/rust-analyzer/rust-analyzer/issues/2922
202 #[test]
203 fn regression_issue_2922() {
204 check_assist(
205 add_explicit_type,
206 r#"
207fn main() {
208 let $0v = [0.0; 2];
209}
210"#,
211 r#"
212fn main() {
213 let v: [f64; 2] = [0.0; 2];
214}
215"#,
216 );
217 // note: this may break later if we add more consteval. it just needs to be something that our
218 // consteval engine doesn't understand
219 check_assist_not_applicable(
220 add_explicit_type,
221 r#"
222fn main() {
223 let $0l = [0.0; 2+2];
224}
225"#,
226 );
227 }
228
201 #[test] 229 #[test]
202 fn default_generics_should_not_be_added() { 230 fn default_generics_should_not_be_added() {
203 check_assist( 231 check_assist(
diff --git a/crates/ide_assists/src/handlers/raw_string.rs b/crates/ide_assists/src/handlers/raw_string.rs
index d0f1613f3..d98a55ae4 100644
--- a/crates/ide_assists/src/handlers/raw_string.rs
+++ b/crates/ide_assists/src/handlers/raw_string.rs
@@ -1,6 +1,6 @@
1use std::borrow::Cow; 1use std::borrow::Cow;
2 2
3use syntax::{ast, AstToken, TextRange, TextSize}; 3use syntax::{ast, ast::IsString, AstToken, TextRange, TextSize};
4 4
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
6 6
diff --git a/crates/ide_assists/src/handlers/replace_string_with_char.rs b/crates/ide_assists/src/handlers/replace_string_with_char.rs
index 634b9c0b7..0800d291e 100644
--- a/crates/ide_assists/src/handlers/replace_string_with_char.rs
+++ b/crates/ide_assists/src/handlers/replace_string_with_char.rs
@@ -1,4 +1,4 @@
1use syntax::{ast, AstToken, SyntaxKind::STRING}; 1use syntax::{ast, ast::IsString, AstToken, SyntaxKind::STRING};
2 2
3use crate::{AssistContext, AssistId, AssistKind, Assists}; 3use crate::{AssistContext, AssistId, AssistKind, Assists};
4 4
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 29d25a58a..4b1e1ccee 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -143,6 +143,30 @@ impl QuoteOffsets {
143 } 143 }
144} 144}
145 145
146pub trait IsString: AstToken {
147 fn quote_offsets(&self) -> Option<QuoteOffsets> {
148 let text = self.text();
149 let offsets = QuoteOffsets::new(text)?;
150 let o = self.syntax().text_range().start();
151 let offsets = QuoteOffsets {
152 quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
153 contents: offsets.contents + o,
154 };
155 Some(offsets)
156 }
157 fn text_range_between_quotes(&self) -> Option<TextRange> {
158 self.quote_offsets().map(|it| it.contents)
159 }
160 fn open_quote_text_range(&self) -> Option<TextRange> {
161 self.quote_offsets().map(|it| it.quotes.0)
162 }
163 fn close_quote_text_range(&self) -> Option<TextRange> {
164 self.quote_offsets().map(|it| it.quotes.1)
165 }
166}
167
168impl IsString for ast::String {}
169
146impl ast::String { 170impl ast::String {
147 pub fn is_raw(&self) -> bool { 171 pub fn is_raw(&self) -> bool {
148 self.text().starts_with('r') 172 self.text().starts_with('r')
@@ -187,32 +211,49 @@ impl ast::String {
187 (false, false) => Some(Cow::Owned(buf)), 211 (false, false) => Some(Cow::Owned(buf)),
188 } 212 }
189 } 213 }
190
191 pub fn quote_offsets(&self) -> Option<QuoteOffsets> {
192 let text = self.text();
193 let offsets = QuoteOffsets::new(text)?;
194 let o = self.syntax().text_range().start();
195 let offsets = QuoteOffsets {
196 quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
197 contents: offsets.contents + o,
198 };
199 Some(offsets)
200 }
201 pub fn text_range_between_quotes(&self) -> Option<TextRange> {
202 self.quote_offsets().map(|it| it.contents)
203 }
204 pub fn open_quote_text_range(&self) -> Option<TextRange> {
205 self.quote_offsets().map(|it| it.quotes.0)
206 }
207 pub fn close_quote_text_range(&self) -> Option<TextRange> {
208 self.quote_offsets().map(|it| it.quotes.1)
209 }
210} 214}
211 215
216impl IsString for ast::ByteString {}
217
212impl ast::ByteString { 218impl ast::ByteString {
213 pub fn is_raw(&self) -> bool { 219 pub fn is_raw(&self) -> bool {
214 self.text().starts_with("br") 220 self.text().starts_with("br")
215 } 221 }
222
223 pub fn value(&self) -> Option<Cow<'_, [u8]>> {
224 if self.is_raw() {
225 let text = self.text();
226 let text =
227 &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
228 return Some(Cow::Borrowed(text.as_bytes()));
229 }
230
231 let text = self.text();
232 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
233
234 let mut buf: Vec<u8> = Vec::new();
235 let mut text_iter = text.chars();
236 let mut has_error = false;
237 unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
238 unescaped_char,
239 buf.capacity() == 0,
240 ) {
241 (Ok(c), false) => buf.push(c as u8),
242 (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
243 (Ok(c), true) => {
244 buf.reserve_exact(text.len());
245 buf.extend_from_slice(&text[..char_range.start].as_bytes());
246 buf.push(c as u8);
247 }
248 (Err(_), _) => has_error = true,
249 });
250
251 match (has_error, buf.capacity() == 0) {
252 (true, _) => None,
253 (false, true) => Some(Cow::Borrowed(text.as_bytes())),
254 (false, false) => Some(Cow::Owned(buf)),
255 }
256 }
216} 257}
217 258
218#[derive(Debug)] 259#[derive(Debug)]