[[package]]
name = "chalk-derive"
version = "0.1.0"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "chalk-engine"
version = "0.9.0"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"chalk-macros",
"rustc-hash",
[[package]]
name = "chalk-ir"
version = "0.1.0"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"chalk-derive",
"chalk-engine",
[[package]]
name = "chalk-macros"
version = "0.1.1"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"lazy_static",
]
[[package]]
name = "chalk-rust-ir"
version = "0.1.0"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"chalk-derive",
"chalk-engine",
[[package]]
name = "chalk-solve"
version = "0.1.0"
-source = "git+https://github.com/rust-lang/chalk.git?rev=6222e416b96892b2a86bc08de7dbc9826ff1acea#6222e416b96892b2a86bc08de7dbc9826ff1acea"
+source = "git+https://github.com/rust-lang/chalk.git?rev=28cef6ff403d403e6ad2f3d27d944e9ffac1bce8#28cef6ff403d403e6ad2f3d27d944e9ffac1bce8"
dependencies = [
"chalk-derive",
"chalk-engine",
[[package]]
name = "hermit-abi"
-version = "0.1.10"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
+checksum = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15"
dependencies = [
"libc",
]
[[package]]
name = "libc"
-version = "0.2.68"
+version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
+checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
[[package]]
name = "libloading"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c979a19ffb457f0273965c333053f3d586bf759bf7b683fbebc37f9a9ebedc4"
+checksum = "3c4f51b790f5bdb65acb4cc94bb81d7b2ee60348a5431ac1467d390b017600b0"
dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "num_cpus"
-version = "1.12.0"
+version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
[[package]]
name = "parking_lot"
-version = "0.10.1"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fdfcb5f20930a79e326f7ec992a9fdb5b7bd809254b1e735bdd5a99f78bee0d"
+checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
dependencies = [
"lock_api",
"parking_lot_core",
scoped-tls = "1"
-chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
-chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
-chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
+chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" }
+chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" }
+chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" }
[dev-dependencies]
insta = "0.16.0"
use crate::{
db::HirDatabase,
expr::{Body, Expr, Literal, Pat, PatId},
- InferenceResult,
+ ApplicationTy, InferenceResult, Ty, TypeCtor,
};
-use hir_def::{adt::VariantData, EnumVariantId, VariantId};
+use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
+use ra_arena::Idx;
#[derive(Debug, Clone, Copy)]
/// Either a pattern from the source code being analyzed, represented as
}
pub struct MatchCheckCtx<'a> {
+ pub match_expr: Idx<Expr>,
pub body: Arc<Body>,
pub infer: Arc<InferenceResult>,
pub db: &'a dyn HirDatabase,
matrix: &Matrix,
v: &PatStack,
) -> MatchCheckResult<Usefulness> {
+ // Handle the special case of enums with no variants. In that case, no match
+ // arm is useful.
+ if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) =
+ cx.infer[cx.match_expr].strip_references()
+ {
+ if cx.db.enum_data(*enum_id).variants.is_empty() {
+ return Ok(Usefulness::NotUseful);
+ }
+ }
+
if v.is_empty() {
let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful };
check_no_diagnostic(content);
}
+
+ #[test]
+ fn enum_never() {
+ let content = r"
+ enum Never {}
+
+ fn test_fn(never: Never) {
+ match never {}
+ }
+ ";
+
+ check_no_diagnostic(content);
+ }
+
+ #[test]
+ fn enum_never_ref() {
+ let content = r"
+ enum Never {}
+
+ fn test_fn(never: &Never) {
+ match never {}
+ }
+ ";
+
+ check_no_diagnostic(content);
+ }
}
#[cfg(test)]
db::HirDatabase,
traits::{InEnvironment, Solution},
utils::generics,
- BoundVar, Canonical, DebruijnIndex, Substs, Ty,
+ BoundVar, Canonical, DebruijnIndex, Obligation, Substs, TraitRef, Ty,
};
const AUTODEREF_RECURSION_LIMIT: usize = 10;
let parameters =
Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
+ // Check that the type implements Deref at all
+ let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
+ let implements_goal = super::Canonical {
+ num_vars: ty.value.num_vars,
+ value: InEnvironment {
+ value: Obligation::Trait(trait_ref),
+ environment: ty.environment.clone(),
+ },
+ };
+ if db.trait_solve(krate, implements_goal).is_none() {
+ return None;
+ }
+
+ // Now do the assoc type projection
let projection = super::traits::ProjectionPredicate {
ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
// they're just being 'passed through'. In the 'standard' case where
// we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
// the case.
+
+ // FIXME: if the trait solver decides to truncate the type, these
+ // assumptions will be broken. We would need to properly introduce
+ // new variables in that case
+
for i in 1..vars.0.num_vars {
if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
{
None => return,
};
- let cx = MatchCheckCtx { body, infer: infer.clone(), db };
+ let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db };
let pats = arms.iter().map(|arm| arm.pat);
let mut seen = Matrix::empty();
var_stack: Vec<TypeVarId>,
}
+#[derive(Debug)]
pub(super) struct Canonicalized<T> {
pub value: Canonical<T>,
free_vars: Vec<InferTy>,
}
}
+ pub fn strip_references(&self) -> &Ty {
+ let mut t: &Ty = self;
+
+ while let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_mutability), parameters }) = t {
+ t = parameters.as_single();
+ }
+
+ t
+ }
+
pub fn as_adt(&self) -> Option<(AdtId, &Substs)> {
match self {
Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => {
#[test]
fn infer_project_associated_type() {
- // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
assert_snapshot!(
infer(r#"
trait Iterable {
[108; 261) '{ ...ter; }': ()
[118; 119) 'x': u32
[145; 146) '1': u32
- [156; 157) 'y': {unknown}
- [183; 192) 'no_matter': {unknown}
- [202; 203) 'z': {unknown}
- [215; 224) 'no_matter': {unknown}
- [234; 235) 'a': {unknown}
- [249; 258) 'no_matter': {unknown}
+ [156; 157) 'y': Iterable::Item<T>
+ [183; 192) 'no_matter': Iterable::Item<T>
+ [202; 203) 'z': Iterable::Item<T>
+ [215; 224) 'no_matter': Iterable::Item<T>
+ [234; 235) 'a': Iterable::Item<T>
+ [249; 258) 'no_matter': Iterable::Item<T>
"###
);
}
"#),
@r###"
[67; 100) '{ ...own; }': ()
- [77; 78) 'y': {unknown}
- [90; 97) 'unknown': {unknown}
+ [77; 78) 'y': u32
+ [90; 97) 'unknown': u32
"###
);
}
fn test() {
let a = Bar;
- let b = a[1];
+ let b = a[1u32];
b<|>;
}
//- /main.rs crate:main deps:std
fn test() {
let a = &[1u32, 2, 3];
- let b = a[1];
+ let b = a[1u32];
b<|>;
}
}
"#,
);
- // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
- // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
- // to the trait env ourselves here; probably Chalk can't do this by itself.
- // assert_eq!(t, "ApplyL::Out<[missing name]>");
- assert_eq!(t, "{unknown}");
+ assert_eq!(t, "ApplyL::Out<T>");
}
#[test]
[263; 264) 'y': impl Trait<Type = i64>
[290; 398) '{ ...r>); }': ()
[296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
- [296; 302) 'get(x)': {unknown}
+ [296; 302) 'get(x)': u32
[300; 301) 'x': T
- [308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown}
- [308; 315) 'get2(x)': {unknown}
+ [308; 312) 'get2': fn get2<u32, T>(T) -> u32
+ [308; 315) 'get2(x)': u32
[313; 314) 'x': T
[321; 324) 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
- [321; 327) 'get(y)': {unknown}
+ [321; 327) 'get(y)': i64
[325; 326) 'y': impl Trait<Type = i64>
- [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> {unknown}
- [333; 340) 'get2(y)': {unknown}
+ [333; 337) 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
+ [333; 340) 'get2(y)': i64
[338; 339) 'y': impl Trait<Type = i64>
[346; 349) 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
[346; 357) 'get(set(S))': u64
#[test]
fn projection_eq_within_chalk() {
- // std::env::set_var("CHALK_DEBUG", "1");
assert_snapshot!(
infer(r#"
trait Trait1 {
[164; 165) 'x': T
[170; 186) '{ ...o(); }': ()
[176; 177) 'x': T
- [176; 183) 'x.foo()': {unknown}
+ [176; 183) 'x.foo()': u32
"###
);
}
[150; 151) 'f': F
[156; 184) '{ ...2)); }': ()
[162; 163) 'f': F
- [162; 181) 'f.call...1, 2))': {unknown}
+ [162; 181) 'f.call...1, 2))': u128
[174; 180) '(1, 2)': (u32, u64)
[175; 176) '1': u32
[178; 179) '2': u64
"#,
), @r###"
[54; 58) 'self': &Self
- [60; 61) 'x': {unknown}
+ [60; 61) 'x': Trait::Item<Self>
[140; 144) 'self': &S
[146; 147) 'x': u32
[161; 175) '{ let y = x; }': ()
}
"#,
);
- // assert_eq!(t, "u32");
- // doesn't currently work, Chalk #234
- assert_eq!(t, "{unknown}");
+ assert_eq!(t, "u32");
+}
+
+#[test]
+fn proc_macro_server_types() {
+ assert_snapshot!(
+ infer_with_mismatches(r#"
+macro_rules! with_api {
+ ($S:ident, $self:ident, $m:ident) => {
+ $m! {
+ TokenStream {
+ fn new() -> $S::TokenStream;
+ },
+ Group {
+ },
+ }
+ };
+}
+macro_rules! associated_item {
+ (type TokenStream) =>
+ (type TokenStream: 'static + Clone;);
+ (type Group) =>
+ (type Group: 'static + Clone;);
+ ($($item:tt)*) => ($($item)*;)
+}
+macro_rules! declare_server_traits {
+ ($($name:ident {
+ $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
+ }),* $(,)?) => {
+ pub trait Types {
+ $(associated_item!(type $name);)*
+ }
+
+ $(pub trait $name: Types {
+ $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)*
+ })*
+
+ pub trait Server: Types $(+ $name)* {}
+ impl<S: Types $(+ $name)*> Server for S {}
+ }
+}
+with_api!(Self, self_, declare_server_traits);
+struct Group {}
+struct TokenStream {}
+struct Rustc;
+impl Types for Rustc {
+ type TokenStream = TokenStream;
+ type Group = Group;
+}
+fn make<T>() -> T { loop {} }
+impl TokenStream for Rustc {
+ fn new() -> Self::TokenStream {
+ let group: Self::Group = make();
+ make()
+ }
+}
+"#, true),
+ @r###"
+ [1115; 1126) '{ loop {} }': T
+ [1117; 1124) 'loop {}': !
+ [1122; 1124) '{}': ()
+ [1190; 1253) '{ ... }': {unknown}
+ [1204; 1209) 'group': {unknown}
+ [1225; 1229) 'make': fn make<{unknown}>() -> {unknown}
+ [1225; 1231) 'make()': {unknown}
+ [1241; 1245) 'make': fn make<{unknown}>() -> {unknown}
+ [1241; 1247) 'make()': {unknown}
+ "###
+ );
}
#[test]
pub(crate) mod chalk;
mod builtin;
-/// This controls the maximum size of types Chalk considers. If we set this too
-/// high, we can run into slow edge cases; if we set it too low, Chalk won't
-/// find some solutions.
-const CHALK_SOLVER_MAX_SIZE: usize = 10;
+// This controls the maximum size of types Chalk considers. If we set this too
+// high, we can run into slow edge cases; if we set it too low, Chalk won't
+// find some solutions.
+// FIXME this is currently hardcoded in the recursive solver
+// const CHALK_SOLVER_MAX_SIZE: usize = 10;
+
/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;
}
fn create_chalk_solver() -> chalk_solve::Solver<Interner> {
- let solver_choice =
- chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None };
+ let solver_choice = chalk_solve::SolverChoice::recursive();
solver_choice.into_solver()
}
}
impl ToChalk for super::ProjectionPredicate {
- type Chalk = chalk_ir::Normalize<Interner>;
+ type Chalk = chalk_ir::AliasEq<Interner>;
- fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Normalize<Interner> {
- chalk_ir::Normalize { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) }
+ fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
+ chalk_ir::AliasEq { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) }
}
- fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::Normalize<Interner>) -> Self {
+ fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self {
unimplemented!()
}
}
fn well_known_trait_id(
&self,
_well_known_trait: chalk_rust_ir::WellKnownTrait,
- ) -> chalk_ir::TraitId<Interner> {
- unimplemented!()
+ ) -> Option<chalk_ir::TraitId<Interner>> {
+ // FIXME tell Chalk about well-known traits (here and in trait_datum)
+ None
}
}
NavigationTarget {
file_id: self.file_id,
name: self.name.clone(),
- kind: self.ptr.kind(),
+ kind: self.kind,
full_range: self.ptr.range(),
focus_range: self.name_range,
container_name: self.container_name.clone(),
let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
for symbol in &symbol_index.symbols[start..end] {
- if self.only_types && !is_type(symbol.ptr.kind()) {
+ if self.only_types && !is_type(symbol.kind) {
continue;
}
if self.exact && symbol.name != self.query {
pub struct FileSymbol {
pub file_id: FileId,
pub name: SmolStr,
+ pub kind: SyntaxKind,
pub ptr: SyntaxNodePtr,
pub name_range: Option<TextRange>,
pub container_name: Option<SmolStr>,
fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
to_symbol(node).map(move |(name, ptr, name_range)| FileSymbol {
name,
+ kind: node.kind(),
ptr,
file_id,
name_range: Some(name_range),
// FIXME: use a more elegant way to re-fetch the node (#1185), make
// `range` private afterwards
let mut ptr = SyntaxNodePtr::new(parent);
- ptr.range = TextRange::offset_len(ptr.range().start(), len);
+ ptr.range = TextRange::offset_len(ptr.range.start(), len);
ptr.to_node(&new_root_node)
}
self.range
}
- pub fn kind(&self) -> SyntaxKind {
- self.kind
- }
-
pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
- if !N::can_cast(self.kind()) {
+ if !N::can_cast(self.kind) {
return None;
}
Some(AstPtr { raw: self, _ty: PhantomData })
}
pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
- if !U::can_cast(self.raw.kind()) {
+ if !U::can_cast(self.raw.kind) {
return None;
}
Some(AstPtr { raw: self.raw, _ty: PhantomData })