From bfbc210bc1216b79e355eb70449caf08dc67d5ad Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 22 May 2020 18:15:53 +0200 Subject: Use Chalk's built-in representation of function item types --- crates/ra_hir_ty/src/db.rs | 5 ++++ crates/ra_hir_ty/src/lib.rs | 6 ++++ crates/ra_hir_ty/src/tests/traits.rs | 42 +++++++++++++++++++++++++++ crates/ra_hir_ty/src/traits/chalk.rs | 39 ++++++++++++++++++++++--- crates/ra_hir_ty/src/traits/chalk/interner.rs | 2 ++ crates/ra_hir_ty/src/traits/chalk/mapping.rs | 26 ++++++++++++++--- crates/ra_hir_ty/src/traits/chalk/tls.rs | 18 ++++++++++-- 7 files changed, 128 insertions(+), 10 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index dfc6c7dd6..0a8bb24ac 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::interned] fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; #[salsa::interned] + fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId; + #[salsa::interned] fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; #[salsa::interned] fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; @@ -94,6 +96,9 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::traits::chalk::impl_datum_query)] fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc; + #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] + fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc; + #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] fn associated_ty_value( &self, diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index e91c9be04..93cb45a64 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -159,6 +159,12 @@ pub enum TypeCtor { pub struct TypeCtorId(salsa::InternId); impl_intern_key!(TypeCtorId); +/// This exists just for Chalk, because Chalk just has a single `FnDefId` where +/// we have different IDs for struct and enum variant constructors. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub struct CallableDefId(salsa::InternId); +impl_intern_key!(CallableDefId); + impl TypeCtor { pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { match self { diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 6826610cb..17c646076 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -2643,6 +2643,48 @@ fn test() { ); } +#[test] +fn builtin_fn_def_copy() { + assert_snapshot!( + infer_with_mismatches(r#" +#[lang = "copy"] +trait Copy {} + +fn foo() {} +fn bar(T) -> T {} +struct Struct(usize); +enum Enum { Variant(usize) } + +trait Test { fn test(&self) -> bool; } +impl Test for T {} + +fn test() { + foo.test(); + bar.test(); + Struct.test(); + Enum::Variant.test(); +} +"#, true), + // wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet + @r###" + 42..44 '{}': () + 61..62 'T': {unknown} + 69..71 '{}': () + 69..71: expected T, got () + 146..150 'self': &Self + 202..282 '{ ...t(); }': () + 208..211 'foo': fn foo() + 208..218 'foo.test()': {unknown} + 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown} + 224..234 'bar.test()': {unknown} + 240..246 'Struct': Struct(usize) -> Struct + 240..253 'Struct.test()': {unknown} + 259..272 'Enum::Variant': Variant(usize) -> Enum + 259..279 'Enum::...test()': {unknown} + "### + ); +} + #[test] fn builtin_sized() { assert_snapshot!( diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e2f2a9ccb..5b0f12a3c 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -14,7 +14,7 @@ use ra_db::{salsa::InternKey, CrateId}; use super::{builtin, AssocTyValue, ChalkContext, Impl}; use crate::{ db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, - DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, + CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, }; use chalk_rust_ir::WellKnownTrait; use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; @@ -54,10 +54,9 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn fn_def_datum( &self, - _fn_def_id: chalk_ir::FnDefId, + fn_def_id: chalk_ir::FnDefId, ) -> Arc> { - // We don't yet provide any FnDefs to Chalk - unimplemented!() + self.db.fn_def_datum(self.krate, fn_def_id) } fn impls_for_trait( @@ -405,6 +404,26 @@ fn type_alias_associated_ty_value( Arc::new(value) } +pub(crate) fn fn_def_datum_query( + db: &dyn HirDatabase, + _krate: CrateId, + fn_def_id: FnDefId, +) -> Arc { + let callable_def: CallableDef = from_chalk(db, fn_def_id); + let generic_params = generics(db.upcast(), callable_def.into()); + let sig = db.callable_item_signature(callable_def); + let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); + let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); + let bound = chalk_rust_ir::FnDefDatumBound { + // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway + argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), + return_type: sig.value.ret().clone().to_chalk(db), + where_clauses, + }; + let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) }; + Arc::new(datum) +} + impl From for crate::TypeCtorId { fn from(struct_id: AdtId) -> Self { struct_id.0 @@ -417,6 +436,18 @@ impl From for AdtId { } } +impl From for crate::CallableDefId { + fn from(fn_def_id: FnDefId) -> Self { + InternKey::from_intern_id(fn_def_id.0) + } +} + +impl From for FnDefId { + fn from(callable_def_id: crate::CallableDefId) -> Self { + chalk_ir::FnDefId(callable_def_id.as_intern_id()) + } +} + impl From for crate::traits::GlobalImplId { fn from(impl_id: ImplId) -> Self { InternKey::from_intern_id(impl_id.0) diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs index 060372819..2a27f8ed8 100644 --- a/crates/ra_hir_ty/src/traits/chalk/interner.rs +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs @@ -20,6 +20,8 @@ pub type ImplId = chalk_ir::ImplId; pub type ImplDatum = chalk_rust_ir::ImplDatum; pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; +pub type FnDefId = chalk_ir::FnDefId; +pub type FnDefDatum = chalk_rust_ir::FnDefDatum; impl chalk_ir::interner::Interner for Interner { type InternedType = Box>; // FIXME use Arc? diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index a83d82fd8..7841a0e21 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -15,8 +15,8 @@ use crate::{ db::HirDatabase, primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, - ApplicationTy, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, Substs, - TraitEnvironment, TraitRef, Ty, TypeCtor, + ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, + Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, }; use super::interner::*; @@ -217,11 +217,14 @@ impl ToChalk for TypeCtor { TypeCtor::Slice => TypeName::Slice, TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), TypeCtor::Str => TypeName::Str, + TypeCtor::FnDef(callable_def) => { + let id = callable_def.to_chalk(db); + TypeName::FnDef(id) + } TypeCtor::Int(Uncertain::Unknown) | TypeCtor::Float(Uncertain::Unknown) | TypeCtor::Adt(_) | TypeCtor::Array - | TypeCtor::FnDef(_) | TypeCtor::FnPtr { .. } | TypeCtor::Never | TypeCtor::Closure { .. } => { @@ -260,7 +263,10 @@ impl ToChalk for TypeCtor { TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), TypeName::Str => TypeCtor::Str, - TypeName::FnDef(_) => unreachable!(), + TypeName::FnDef(fn_def_id) => { + let callable_def = from_chalk(db, fn_def_id); + TypeCtor::FnDef(callable_def) + } TypeName::Error => { // this should not be reached, since we don't represent TypeName::Error with TypeCtor @@ -347,6 +353,18 @@ impl ToChalk for Impl { } } +impl ToChalk for CallableDef { + type Chalk = FnDefId; + + fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { + db.intern_callable_def(self).into() + } + + fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef { + db.lookup_intern_callable_def(fn_def_id.into()) + } +} + impl ToChalk for TypeAliasId { type Chalk = AssocTypeId; diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index ebf402a07..d88828c7c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs @@ -247,10 +247,24 @@ impl DebugContext<'_> { pub fn debug_fn_def_id( &self, - _fn_def_id: chalk_ir::FnDefId, + fn_def_id: chalk_ir::FnDefId, fmt: &mut fmt::Formatter<'_>, ) -> Result<(), fmt::Error> { - write!(fmt, "fn") + let def: CallableDef = from_chalk(self.0, fn_def_id); + let name = match def { + CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), + CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), + CallableDef::EnumVariantId(e) => { + let enum_data = self.0.enum_data(e.parent); + enum_data.variants[e.local_id].name.clone() + } + }; + match def { + CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name), + CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { + write!(fmt, "{{ctor {}}}", name) + } + } } pub fn debug_const( -- cgit v1.2.3 From 194dd9eb0d44284f7e952a1e84296fcda4d90f5e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 22 May 2020 19:13:17 +0200 Subject: Use Chalk's Ty::Function for function pointer types Function pointers can be 'higher-ranked' over lifetimes, which is why they're not an application type in Chalk, but since we don't model lifetimes it doesn't matter for us yet. --- crates/ra_hir_ty/src/tests/traits.rs | 32 ++++++++++++++++++++++++++++ crates/ra_hir_ty/src/traits/chalk/mapping.rs | 27 ++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 17c646076..0419bc751 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -2685,6 +2685,38 @@ fn test() { ); } +#[test] +fn builtin_fn_ptr_copy() { + assert_snapshot!( + infer_with_mismatches(r#" +#[lang = "copy"] +trait Copy {} + +trait Test { fn test(&self) -> bool; } +impl Test for T {} + +fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { + f1.test(); + f2.test(); + f3.test(); +} +"#, true), + @r###" + 55..59 'self': &Self + 109..111 'f1': fn() + 119..121 'f2': fn(usize) -> u8 + 140..142 'f3': fn(u8, u8) -> &u8 + 163..211 '{ ...t(); }': () + 169..171 'f1': fn() + 169..178 'f1.test()': bool + 184..186 'f2': fn(usize) -> u8 + 184..193 'f2.test()': bool + 199..201 'f3': fn(u8, u8) -> &u8 + 199..208 'f3.test()': bool + "### + ); +} + #[test] fn builtin_sized() { assert_snapshot!( diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 7841a0e21..7082cb095 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -26,14 +26,19 @@ impl ToChalk for Ty { type Chalk = chalk_ir::Ty; fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty { match self { - Ty::Apply(apply_ty) => { - if let TypeCtor::Ref(m) = apply_ty.ctor { - return ref_to_chalk(db, m, apply_ty.parameters); + Ty::Apply(apply_ty) => match apply_ty.ctor { + TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), + TypeCtor::FnPtr { num_args: _ } => { + let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); + chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) + .intern(&Interner) } - let name = apply_ty.ctor.to_chalk(db); - let substitution = apply_ty.parameters.to_chalk(db); - chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) - } + _ => { + let name = apply_ty.ctor.to_chalk(db); + let substitution = apply_ty.parameters.to_chalk(db); + chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) + } + }, Ty::Projection(proj_ty) => { let associated_ty_id = proj_ty.associated_ty.to_chalk(db); let substitution = proj_ty.parameters.to_chalk(db); @@ -93,7 +98,13 @@ impl ToChalk for Ty { Ty::Projection(ProjectionTy { associated_ty, parameters }) } chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), - chalk_ir::TyData::Function(_) => unimplemented!(), + chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { + let parameters: Substs = from_chalk(db, substitution); + Ty::Apply(ApplicationTy { + ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, + parameters, + }) + } chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, chalk_ir::TyData::Dyn(where_clauses) => { -- cgit v1.2.3 From a5cc9a8a9ba1e6a0fc281e149881abdd3bd075c1 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 25 May 2020 13:35:52 -0400 Subject: Fix some clippy perf warnings --- crates/ra_hir_ty/src/traits/builtin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index ccab246bf..88a422d2c 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs @@ -290,8 +290,7 @@ fn trait_object_unsize_impl_datum( let self_trait_ref = TraitRef { trait_, substs: self_substs }; let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; - let impl_substs = - Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build(); + let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build(); let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; -- cgit v1.2.3 From c011f04f55e82c5a057772fa3fb7a1c4d328c6d2 Mon Sep 17 00:00:00 2001 From: Cadu Date: Wed, 27 May 2020 13:15:19 -0300 Subject: Fixed missing newline on each field on "Missing structure fields". --- crates/ra_hir_ty/src/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 41ac70272..2c7298714 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs @@ -40,7 +40,7 @@ impl Diagnostic for MissingFields { fn message(&self) -> String { let mut buf = String::from("Missing structure fields:\n"); for field in &self.missed_fields { - format_to!(buf, "- {}", field); + format_to!(buf, "- {}\n", field); } buf } @@ -73,7 +73,7 @@ impl Diagnostic for MissingPatFields { fn message(&self) -> String { let mut buf = String::from("Missing structure fields:\n"); for field in &self.missed_fields { - format_to!(buf, "- {}", field); + format_to!(buf, "- {}\n", field); } buf } -- cgit v1.2.3 From c8a4bb1445e214dc7105de547bd999ad270e7b42 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 27 May 2020 21:05:21 +0200 Subject: Upgrade Chalk Chalk newly added TypeName::Never and Array; I implemented the conversion for Never, but not Array since that expects a const argument. --- crates/ra_hir_ty/Cargo.toml | 5 ++- crates/ra_hir_ty/src/traits/chalk.rs | 50 +++++++++++++-------------- crates/ra_hir_ty/src/traits/chalk/interner.rs | 14 ++++---- crates/ra_hir_ty/src/traits/chalk/mapping.rs | 40 ++++++++++----------- 4 files changed, 54 insertions(+), 55 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index b2de7fa34..6afed58a1 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -27,9 +27,8 @@ test_utils = { path = "../test_utils" } scoped-tls = "1" -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "5a3b871ca17529ab5aa5787594fabad1634936cb" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "5a3b871ca17529ab5aa5787594fabad1634936cb" } [dev-dependencies] insta = "0.16.0" diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 5b0f12a3c..61de3cc30 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use log::debug; use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; +use chalk_solve::rust_ir::{self, WellKnownTrait}; use hir_def::{ lang_item::{lang_attr, LangItemTarget}, @@ -16,7 +17,6 @@ use crate::{ db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, }; -use chalk_rust_ir::WellKnownTrait; use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; pub use self::interner::*; @@ -55,7 +55,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn fn_def_datum( &self, fn_def_id: chalk_ir::FnDefId, - ) -> Arc> { + ) -> Arc> { self.db.fn_def_datum(self.krate, fn_def_id) } @@ -112,7 +112,7 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { } fn well_known_trait_id( &self, - well_known_trait: chalk_rust_ir::WellKnownTrait, + well_known_trait: rust_ir::WellKnownTrait, ) -> Option> { let lang_attr = lang_attr_from_well_known_trait(well_known_trait); let lang_items = self.db.crate_lang_items(self.krate); @@ -133,13 +133,13 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { fn opaque_ty_data( &self, _id: chalk_ir::OpaqueTyId, - ) -> Arc> { + ) -> Arc> { unimplemented!() } fn force_impl_for( &self, - _well_known: chalk_rust_ir::WellKnownTrait, + _well_known: rust_ir::WellKnownTrait, _ty: &chalk_ir::TyData, ) -> Option { // this method is mostly for rustc @@ -150,6 +150,10 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { // FIXME: implement actual object safety true } + + fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { + Ty::Unknown.to_chalk(self.db) + } } pub(crate) fn program_clauses_for_chalk_env_query( @@ -188,7 +192,7 @@ pub(crate) fn associated_ty_data_query( .collect(); let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); - let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; + let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; let datum = AssociatedTyDatum { trait_id: trait_.to_chalk(db), id, @@ -209,7 +213,7 @@ pub(crate) fn trait_datum_query( debug!("trait {:?} = {:?}", trait_id, trait_data.name); let generic_params = generics(db.upcast(), trait_.into()); let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); - let flags = chalk_rust_ir::TraitFlags { + let flags = rust_ir::TraitFlags { auto: trait_data.auto, upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, non_enumerable: true, @@ -221,7 +225,7 @@ pub(crate) fn trait_datum_query( let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); let associated_ty_ids = trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); - let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; + let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; let well_known = lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); let trait_datum = TraitDatum { @@ -271,12 +275,12 @@ pub(crate) fn struct_datum_query( convert_where_clauses(db, generic_def, &bound_vars) }) .unwrap_or_else(Vec::new); - let flags = chalk_rust_ir::AdtFlags { + let flags = rust_ir::AdtFlags { upstream, // FIXME set fundamental flag correctly fundamental: false, }; - let struct_datum_bound = chalk_rust_ir::AdtDatumBound { + let struct_datum_bound = rust_ir::AdtDatumBound { fields: Vec::new(), // FIXME add fields (only relevant for auto traits) where_clauses, }; @@ -316,9 +320,9 @@ fn impl_def_datum( let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); let trait_ = trait_ref.trait_; let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { - chalk_rust_ir::ImplType::Local + rust_ir::ImplType::Local } else { - chalk_rust_ir::ImplType::External + rust_ir::ImplType::External }; let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); let negative = impl_data.is_negative; @@ -331,13 +335,9 @@ fn impl_def_datum( ); let trait_ref = trait_ref.to_chalk(db); - let polarity = if negative { - chalk_rust_ir::Polarity::Negative - } else { - chalk_rust_ir::Polarity::Positive - }; + let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; - let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses }; + let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; let trait_data = db.trait_data(trait_); let associated_ty_value_ids = impl_data .items @@ -395,8 +395,8 @@ fn type_alias_associated_ty_value( .associated_type_by_name(&type_alias_data.name) .expect("assoc ty value should not exist"); // validated when building the impl data as well let ty = db.ty(type_alias.into()); - let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; - let value = chalk_rust_ir::AssociatedTyValue { + let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; + let value = rust_ir::AssociatedTyValue { impl_id: Impl::ImplDef(impl_id).to_chalk(db), associated_ty_id: assoc_ty.to_chalk(db), value: make_binders(value_bound, ty.num_binders), @@ -414,7 +414,7 @@ pub(crate) fn fn_def_datum_query( let sig = db.callable_item_signature(callable_def); let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); - let bound = chalk_rust_ir::FnDefDatumBound { + let bound = rust_ir::FnDefDatumBound { // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), return_type: sig.value.ret().clone().to_chalk(db), @@ -460,14 +460,14 @@ impl From for ImplId { } } -impl From> for crate::traits::AssocTyValueId { - fn from(id: chalk_rust_ir::AssociatedTyValueId) -> Self { +impl From> for crate::traits::AssocTyValueId { + fn from(id: rust_ir::AssociatedTyValueId) -> Self { Self::from_intern_id(id.0) } } -impl From for chalk_rust_ir::AssociatedTyValueId { +impl From for rust_ir::AssociatedTyValueId { fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { - chalk_rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) + rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) } } diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs index 2a27f8ed8..e27074ba6 100644 --- a/crates/ra_hir_ty/src/traits/chalk/interner.rs +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs @@ -11,17 +11,17 @@ use std::{fmt, sync::Arc}; pub struct Interner; pub type AssocTypeId = chalk_ir::AssocTypeId; -pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum; +pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum; pub type TraitId = chalk_ir::TraitId; -pub type TraitDatum = chalk_rust_ir::TraitDatum; +pub type TraitDatum = chalk_solve::rust_ir::TraitDatum; pub type AdtId = chalk_ir::AdtId; -pub type StructDatum = chalk_rust_ir::AdtDatum; +pub type StructDatum = chalk_solve::rust_ir::AdtDatum; pub type ImplId = chalk_ir::ImplId; -pub type ImplDatum = chalk_rust_ir::ImplDatum; -pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; -pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue; +pub type ImplDatum = chalk_solve::rust_ir::ImplDatum; +pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId; +pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue; pub type FnDefId = chalk_ir::FnDefId; -pub type FnDefDatum = chalk_rust_ir::FnDefDatum; +pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum; impl chalk_ir::interner::Interner for Interner { type InternedType = Box>; // FIXME use Arc? diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 7082cb095..5f6daf842 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs @@ -7,6 +7,7 @@ use chalk_ir::{ cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, UniverseIndex, }; +use chalk_solve::rust_ir; use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; use ra_db::salsa::InternKey; @@ -106,7 +107,7 @@ impl ToChalk for Ty { }) } chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), - chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, + chalk_ir::TyData::InferenceVar(_iv, _kind) => Ty::Unknown, chalk_ir::TyData::Dyn(where_clauses) => { assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); let predicates = where_clauses @@ -232,12 +233,13 @@ impl ToChalk for TypeCtor { let id = callable_def.to_chalk(db); TypeName::FnDef(id) } + TypeCtor::Never => TypeName::Never, + TypeCtor::Int(Uncertain::Unknown) | TypeCtor::Float(Uncertain::Unknown) | TypeCtor::Adt(_) | TypeCtor::Array | TypeCtor::FnPtr { .. } - | TypeCtor::Never | TypeCtor::Closure { .. } => { // other TypeCtors get interned and turned into a chalk StructId let struct_id = db.intern_type_ctor(self).into(); @@ -273,13 +275,14 @@ impl ToChalk for TypeCtor { TypeName::Slice => TypeCtor::Slice, TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), TypeName::Str => TypeCtor::Str, + TypeName::Never => TypeCtor::Never, TypeName::FnDef(fn_def_id) => { let callable_def = from_chalk(db, fn_def_id); TypeCtor::FnDef(callable_def) } - TypeName::Error => { + TypeName::Array | TypeName::Error => { // this should not be reached, since we don't represent TypeName::Error with TypeCtor unreachable!() } @@ -508,7 +511,7 @@ where fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical { let parameter = chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty, + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), chalk_ir::UniverseIndex::ROOT, ); let value = self.value.to_chalk(db); @@ -579,17 +582,17 @@ impl ToChalk for builtin::BuiltinImplData { type Chalk = ImplDatum; fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { - let impl_type = chalk_rust_ir::ImplType::External; + let impl_type = rust_ir::ImplType::External; let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); let impl_datum_bound = - chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; + rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; let associated_ty_value_ids = self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); - chalk_rust_ir::ImplDatum { + rust_ir::ImplDatum { binders: make_binders(impl_datum_bound, self.num_vars), impl_type, - polarity: chalk_rust_ir::Polarity::Positive, + polarity: rust_ir::Polarity::Positive, associated_ty_value_ids, } } @@ -604,9 +607,9 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData { fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { let ty = self.value.to_chalk(db); - let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; + let value_bound = rust_ir::AssociatedTyValueBound { ty }; - chalk_rust_ir::AssociatedTyValue { + rust_ir::AssociatedTyValue { associated_ty_id: self.assoc_ty_id.to_chalk(db), impl_id: self.impl_.to_chalk(db), value: make_binders(value_bound, self.num_vars), @@ -628,7 +631,7 @@ where chalk_ir::Binders::new( chalk_ir::VariableKinds::from( &Interner, - std::iter::repeat(chalk_ir::VariableKind::Ty).take(num_vars), + std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars), ), value, ) @@ -655,7 +658,7 @@ pub(super) fn generic_predicate_to_inline_bound( db: &dyn HirDatabase, pred: &GenericPredicate, self_ty: &Ty, -) -> Option> { +) -> Option> { // An InlineBound is like a GenericPredicate, except the self type is left out. // We don't have a special type for this, but Chalk does. match pred { @@ -670,8 +673,8 @@ pub(super) fn generic_predicate_to_inline_bound( .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) .collect(); let trait_bound = - chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; - Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) + rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; + Some(rust_ir::InlineBound::TraitBound(trait_bound)) } GenericPredicate::Projection(proj) => { if &proj.projection_ty.parameters[0] != self_ty { @@ -685,16 +688,13 @@ pub(super) fn generic_predicate_to_inline_bound( .iter() .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) .collect(); - let alias_eq_bound = chalk_rust_ir::AliasEqBound { + let alias_eq_bound = rust_ir::AliasEqBound { value: proj.ty.clone().to_chalk(db), - trait_bound: chalk_rust_ir::TraitBound { - trait_id: trait_.to_chalk(db), - args_no_self, - }, + trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), parameters: Vec::new(), // FIXME we don't support generic associated types yet }; - Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) + Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) } GenericPredicate::Error => None, } -- cgit v1.2.3 From 367487fe88dca78cffad5138673d5259f7f7ba6b Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 28 May 2020 21:42:22 +0200 Subject: Support raw_ref_op's raw reference operator --- crates/ra_hir_ty/src/infer/expr.rs | 37 +++++++++++++++++++++------------- crates/ra_hir_ty/src/lib.rs | 18 +++++++++++++++-- crates/ra_hir_ty/src/tests/coercion.rs | 17 ++++++++++------ crates/ra_hir_ty/src/tests/simple.rs | 20 ++++++++++++++++++ 4 files changed, 70 insertions(+), 22 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b28724f0e..54bab3476 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -17,8 +17,8 @@ use crate::{ autoderef, method_resolution, op, traits::InEnvironment, utils::{generics, variant_data, Generics}, - ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, - Ty, TypeCtor, Uncertain, + ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, + TraitRef, Ty, TypeCtor, Uncertain, }; use super::{ @@ -350,19 +350,28 @@ impl<'a> InferenceContext<'a> { // FIXME check the cast... cast_ty } - Expr::Ref { expr, mutability } => { - let expectation = - if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() { - if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { - // FIXME: throw type error - expected mut reference but found shared ref, - // which cannot be coerced - } - Expectation::rvalue_hint(Ty::clone(exp_inner)) - } else { - Expectation::none() - }; + Expr::Ref { expr, rawness, mutability } => { + let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = + &expected.ty.as_reference_or_ptr() + { + if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { + // FIXME: throw type error - expected mut reference but found shared ref, + // which cannot be coerced + } + if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { + // FIXME: throw type error - expected reference but found ptr, + // which cannot be coerced + } + Expectation::rvalue_hint(Ty::clone(exp_inner)) + } else { + Expectation::none() + }; let inner_ty = self.infer_expr_inner(*expr, &expectation); - Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) + let ty = match rawness { + Rawness::RawPtr => TypeCtor::RawPtr(*mutability), + Rawness::Ref => TypeCtor::Ref(*mutability), + }; + Ty::apply_one(ty, inner_ty) } Expr::Box { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 93cb45a64..9fa8d3bdc 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -49,8 +49,10 @@ use std::sync::Arc; use std::{iter, mem}; use hir_def::{ - expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, - HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, + expr::ExprId, + type_ref::{Mutability, Rawness}, + AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, + TypeParamId, }; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -709,6 +711,18 @@ impl Ty { } } + pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { + match self { + Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { + Some((parameters.as_single(), Rawness::Ref, *mutability)) + } + Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => { + Some((parameters.as_single(), Rawness::RawPtr, *mutability)) + } + _ => None, + } + } + pub fn strip_references(&self) -> &Ty { let mut t: &Ty = self; diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 2cc4f4bf9..6f777ed8c 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() { assert_snapshot!( infer(r#" fn test() { - let x: &[i32] = &[1]; + let x: &[isize] = &[1]; + let x: *const [isize] = &[1]; } "#), @r###" - 11..40 '{ ...[1]; }': () - 21..22 'x': &[i32] - 33..37 '&[1]': &[i32; _] - 34..37 '[1]': [i32; _] - 35..36 '1': i32 + 11..76 '{ ...[1]; }': () + 21..22 'x': &[isize] + 35..39 '&[1]': &[isize; _] + 36..39 '[1]': [isize; _] + 37..38 '1': isize + 49..50 'x': *const [isize] + 69..73 '&[1]': &[isize; _] + 70..73 '[1]': [isize; _] + 71..72 '1': isize "###); } diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index fd2208af2..f1db34160 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -384,6 +384,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { ); } +#[test] +fn infer_raw_ref() { + assert_snapshot!( + infer(r#" +fn test(a: i32) { + &raw mut a; + &raw const a; +} +"#), + @r###" + 9..10 'a': i32 + 17..54 '{ ...t a; }': () + 23..33 '&raw mut a': *mut i32 + 32..33 'a': i32 + 39..51 '&raw const a': *const i32 + 50..51 'a': i32 + "### + ); +} + #[test] fn infer_literals() { assert_snapshot!( -- cgit v1.2.3 From 7d0586cb15000193941f93d4b5281e56ef751edd Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 29 May 2020 16:03:06 +0200 Subject: Use first match branch in case of type mismatch, not last The comment says this was intentional, but I do agree with #4304 that it makes more sense the other way around (for if/else as well). Fixes #4304. --- crates/ra_hir_ty/src/infer/coerce.rs | 4 +--- crates/ra_hir_ty/src/tests/simple.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 2ee9adb16..32c7c57cd 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -45,9 +45,7 @@ impl<'a> InferenceContext<'a> { self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) } else { mark::hit!(coerce_merge_fail_fallback); - // For incompatible types, we use the latter one as result - // to be better recovery for `if` without `else`. - ty2.clone() + ty1.clone() } } } diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index fd2208af2..daa9cc953 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -937,7 +937,7 @@ fn main(foo: Foo) { 51..107 'if tru... }': () 54..58 'true': bool 59..67 '{ }': () - 73..107 'if fal... }': () + 73..107 'if fal... }': i32 76..81 'false': bool 82..107 '{ ... }': i32 92..95 'foo': Foo -- cgit v1.2.3 From ab28f6c24909f2424c6f1d85d1518fa4269fbaae Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 29 May 2020 16:49:52 +0200 Subject: Upgrade Chalk Fixes #4072. --- crates/ra_hir_ty/Cargo.toml | 4 +-- crates/ra_hir_ty/src/tests/traits.rs | 54 ++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 6afed58a1..4b8dcdc07 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" } scoped-tls = "1" -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "5a3b871ca17529ab5aa5787594fabad1634936cb" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "5a3b871ca17529ab5aa5787594fabad1634936cb" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } [dev-dependencies] insta = "0.16.0" diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 0419bc751..e8778d419 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -2665,7 +2665,6 @@ fn test() { Enum::Variant.test(); } "#, true), - // wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet @r###" 42..44 '{}': () 61..62 'T': {unknown} @@ -2674,13 +2673,13 @@ fn test() { 146..150 'self': &Self 202..282 '{ ...t(); }': () 208..211 'foo': fn foo() - 208..218 'foo.test()': {unknown} + 208..218 'foo.test()': bool 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown} - 224..234 'bar.test()': {unknown} + 224..234 'bar.test()': bool 240..246 'Struct': Struct(usize) -> Struct - 240..253 'Struct.test()': {unknown} + 240..253 'Struct.test()': bool 259..272 'Enum::Variant': Variant(usize) -> Enum - 259..279 'Enum::...test()': {unknown} + 259..279 'Enum::...test()': bool "### ); } @@ -2754,3 +2753,48 @@ fn test() { "### ); } + +#[test] +fn integer_range_iterate() { + let t = type_at( + r#" +//- /main.rs crate:main deps:std +fn test() { + for x in 0..100 { x<|>; } +} + +//- /std.rs crate:std +pub mod ops { + pub struct Range { + pub start: Idx, + pub end: Idx, + } +} + +pub mod iter { + pub trait Iterator { + type Item; + } + + pub trait IntoIterator { + type Item; + type IntoIter: Iterator; + } + + impl IntoIterator for T where T: Iterator { + type Item = ::Item; + type IntoIter = Self; + } +} + +trait Step {} +impl Step for i32 {} +impl Step for i64 {} + +impl iter::Iterator for ops::Range { + type Item = A; +} +"#, + ); + assert_eq!(t, "i32"); +} -- cgit v1.2.3 From 6f67a46a6a264ac7985a10ee19fbf9bbaef924bc Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 29 May 2020 17:35:57 +0200 Subject: Fix match ergonomics in closure parameters Fixes #4476. --- crates/ra_hir_ty/src/infer/expr.rs | 16 +++++++---- crates/ra_hir_ty/src/tests/patterns.rs | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 54bab3476..78084cb57 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -140,13 +140,13 @@ impl<'a> InferenceContext<'a> { let mut sig_tys = Vec::new(); - for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { - let expected = if let Some(type_ref) = arg_type { + // collect explicitly written argument types + for arg_type in arg_types.iter() { + let arg_ty = if let Some(type_ref) = arg_type { self.make_ty(type_ref) } else { - Ty::Unknown + self.table.new_type_var() }; - let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default()); sig_tys.push(arg_ty); } @@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> { sig_tys.push(ret_ty.clone()); let sig_ty = Ty::apply( TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, - Substs(sig_tys.into()), + Substs(sig_tys.clone().into()), ); let closure_ty = Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); @@ -168,6 +168,12 @@ impl<'a> InferenceContext<'a> { // infer the body. self.coerce(&closure_ty, &expected.ty); + // Now go through the argument patterns + for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { + let resolved = self.resolve_ty_as_possible(arg_ty); + self.infer_pat(*arg_pat, &resolved, BindingMode::default()); + } + let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index 0c5f972a2..fe62587c0 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs @@ -520,3 +520,53 @@ fn main() { 105..107 '()': () ") } + +#[test] +fn match_ergonomics_in_closure_params() { + assert_snapshot!( + infer(r#" +#[lang = "fn_once"] +trait FnOnce { + type Output; +} + +fn foo U>(t: T, f: F) -> U { loop {} } + +fn test() { + foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics + foo(&(1, "a"), |(x, y)| x); +} +"#), + @r###" + 94..95 't': T + 100..101 'f': F + 111..122 '{ loop {} }': U + 113..120 'loop {}': ! + 118..120 '{}': () + 134..233 '{ ... x); }': () + 140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 + 140..167 'foo(&(...y)| x)': i32 + 144..153 '&(1, "a")': &(i32, &str) + 145..153 '(1, "a")': (i32, &str) + 146..147 '1': i32 + 149..152 '"a"': &str + 155..166 '|&(x, y)| x': |&(i32, &str)| -> i32 + 156..163 '&(x, y)': &(i32, &str) + 157..163 '(x, y)': (i32, &str) + 158..159 'x': i32 + 161..162 'y': &str + 165..166 'x': i32 + 204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 + 204..230 'foo(&(...y)| x)': &i32 + 208..217 '&(1, "a")': &(i32, &str) + 209..217 '(1, "a")': (i32, &str) + 210..211 '1': i32 + 213..216 '"a"': &str + 219..229 '|(x, y)| x': |&(i32, &str)| -> &i32 + 220..226 '(x, y)': (i32, &str) + 221..222 'x': &i32 + 224..225 'y': &&str + 228..229 'x': &i32 + "### + ); +} -- cgit v1.2.3 From fb469c3b31e7da962e91269b53b2f53d672cc4ba Mon Sep 17 00:00:00 2001 From: robojumper Date: Sat, 30 May 2020 02:06:58 +0200 Subject: labelled break test --- crates/ra_hir_ty/src/tests/simple.rs | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 839491b9e..beceb8634 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1943,3 +1943,57 @@ fn test() { "### ); } + +#[test] +fn infer_labelled_break_with_val() { + assert_snapshot!( + infer(r#" +fn foo() { + let _x = || 'outer: loop { + let inner = 'inner: loop { + let i = Default::default(); + if (break 'outer i) { + loop { break 'inner 5i8; }; + } else if true { + break 'inner 6; + } + break 7; + }; + break inner < 8; + }; +} +"#), + @r###" + 10..336 '{ ... }; }': () + 20..22 '_x': || -> bool + 25..333 '|| 'ou... }': || -> bool + 28..333 ''outer... }': bool + 41..333 '{ ... }': () + 55..60 'inner': i32 + 63..301 ''inner... }': i32 + 76..301 '{ ... }': () + 94..95 'i': i32 + 98..114 'Defaul...efault': {unknown} + 98..116 'Defaul...ault()': i32 + 130..270 'if (br... }': () + 134..148 'break 'outer i': ! + 147..148 'i': i32 + 150..209 '{ ... }': () + 168..194 'loop {...5i8; }': i8 + 173..194 '{ brea...5i8; }': () + 175..191 'break ...er 5i8': ! + 188..191 '5i8': i8 + 215..270 'if tru... }': () + 218..222 'true': bool + 223..270 '{ ... }': () + 241..255 'break 'inner 6': ! + 254..255 '6': i32 + 283..290 'break 7': ! + 289..290 '7': i32 + 311..326 'break inner < 8': ! + 317..322 'inner': i32 + 317..326 'inner < 8': bool + 325..326 '8': i32 + "### + ); +} -- cgit v1.2.3 From 1cd78a3355ea70d3070cabb00c80a5d195499752 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sun, 31 May 2020 10:59:40 +0200 Subject: correctly infer labelled breaks --- crates/ra_hir_ty/src/infer.rs | 11 +++++++++ crates/ra_hir_ty/src/infer/expr.rs | 45 +++++++++++++++++++++++------------- crates/ra_hir_ty/src/tests/simple.rs | 20 ++++++++-------- 3 files changed, 50 insertions(+), 26 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 957d6e0b5..dc77e88e5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -219,6 +219,17 @@ struct InferenceContext<'a> { struct BreakableContext { pub may_break: bool, pub break_ty: Ty, + pub label: Option, +} + +fn find_breakable<'c>( + ctxs: &'c mut [BreakableContext], + label: Option<&name::Name>, +) -> Option<&'c mut BreakableContext> { + match label { + Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), + None => ctxs.last_mut(), + } } impl<'a> InferenceContext<'a> { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 78084cb57..4a98e2deb 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -22,8 +22,8 @@ use crate::{ }; use super::{ - BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, - TypeMismatch, + find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, + InferenceDiagnostic, TypeMismatch, }; impl<'a> InferenceContext<'a> { @@ -86,16 +86,20 @@ impl<'a> InferenceContext<'a> { self.coerce_merge_branch(&then_ty, &else_ty) } - Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), + Expr::Block { statements, tail, .. } => { + // FIXME: Breakable block inference + self.infer_block(statements, *tail, expected) + } Expr::TryBlock { body } => { let _inner = self.infer_expr(*body, expected); // FIXME should be std::result::Result<{inner}, _> Ty::Unknown } - Expr::Loop { body } => { + Expr::Loop { body, label } => { self.breakables.push(BreakableContext { may_break: false, break_ty: self.table.new_type_var(), + label: label.clone(), }); self.infer_expr(*body, &Expectation::has_type(Ty::unit())); @@ -110,8 +114,12 @@ impl<'a> InferenceContext<'a> { Ty::simple(TypeCtor::Never) } } - Expr::While { condition, body } => { - self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); + Expr::While { condition, body, label } => { + self.breakables.push(BreakableContext { + may_break: false, + break_ty: Ty::Unknown, + label: label.clone(), + }); // while let is desugared to a match loop, so this is always simple while self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); self.infer_expr(*body, &Expectation::has_type(Ty::unit())); @@ -120,10 +128,14 @@ impl<'a> InferenceContext<'a> { self.diverges = Diverges::Maybe; Ty::unit() } - Expr::For { iterable, body, pat } => { + Expr::For { iterable, body, pat, label } => { let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); + self.breakables.push(BreakableContext { + may_break: false, + break_ty: Ty::Unknown, + label: label.clone(), + }); let pat_ty = self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); @@ -236,23 +248,24 @@ impl<'a> InferenceContext<'a> { let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) } - Expr::Continue => Ty::simple(TypeCtor::Never), - Expr::Break { expr } => { + Expr::Continue { .. } => Ty::simple(TypeCtor::Never), + Expr::Break { expr, label } => { let val_ty = if let Some(expr) = expr { self.infer_expr(*expr, &Expectation::none()) } else { Ty::unit() }; - let last_ty = if let Some(ctxt) = self.breakables.last() { - ctxt.break_ty.clone() - } else { - Ty::Unknown - }; + let last_ty = + if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { + ctxt.break_ty.clone() + } else { + Ty::Unknown + }; let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); - if let Some(ctxt) = self.breakables.last_mut() { + if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { ctxt.break_ty = merged_type; ctxt.may_break = true; } else { diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index beceb8634..88309157b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1969,17 +1969,17 @@ fn foo() { 25..333 '|| 'ou... }': || -> bool 28..333 ''outer... }': bool 41..333 '{ ... }': () - 55..60 'inner': i32 - 63..301 ''inner... }': i32 + 55..60 'inner': i8 + 63..301 ''inner... }': i8 76..301 '{ ... }': () - 94..95 'i': i32 + 94..95 'i': bool 98..114 'Defaul...efault': {unknown} - 98..116 'Defaul...ault()': i32 + 98..116 'Defaul...ault()': bool 130..270 'if (br... }': () 134..148 'break 'outer i': ! - 147..148 'i': i32 + 147..148 'i': bool 150..209 '{ ... }': () - 168..194 'loop {...5i8; }': i8 + 168..194 'loop {...5i8; }': ! 173..194 '{ brea...5i8; }': () 175..191 'break ...er 5i8': ! 188..191 '5i8': i8 @@ -1987,13 +1987,13 @@ fn foo() { 218..222 'true': bool 223..270 '{ ... }': () 241..255 'break 'inner 6': ! - 254..255 '6': i32 + 254..255 '6': i8 283..290 'break 7': ! - 289..290 '7': i32 + 289..290 '7': i8 311..326 'break inner < 8': ! - 317..322 'inner': i32 + 317..322 'inner': i8 317..326 'inner < 8': bool - 325..326 '8': i32 + 325..326 '8': i8 "### ); } -- cgit v1.2.3