From 7886513f89795e06eef258e0c54dbd1224c98317 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 22:05:31 +0200 Subject: Nicer display of closures in Chalk logs --- crates/ra_hir_ty/src/traits/chalk/tls.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index d9bbb54a5..0a8932dae 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs @@ -5,7 +5,7 @@ use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplicati use super::{from_chalk, Interner}; use crate::{db::HirDatabase, CallableDef, TypeCtor}; -use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; +use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; pub use unsafe_tls::{set_current_program, with_current_program}; @@ -69,7 +69,27 @@ impl DebugContext<'_> { write!(f, "{}::{}", trait_name, name)?; } TypeCtor::Closure { def, expr } => { - write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?; + write!(f, "{{closure {:?} in ", expr.into_raw())?; + match def { + DefWithBodyId::FunctionId(func) => { + write!(f, "fn {}", self.0.function_data(func).name)? + } + DefWithBodyId::StaticId(s) => { + if let Some(name) = self.0.static_data(s).name.as_ref() { + write!(f, "body of static {}", name)?; + } else { + write!(f, "body of unnamed static {:?}", s)?; + } + } + DefWithBodyId::ConstId(c) => { + if let Some(name) = self.0.const_data(c).name.as_ref() { + write!(f, "body of const {}", name)?; + } else { + write!(f, "body of unnamed const {:?}", c)?; + } + } + }; + write!(f, "}}")?; } } Ok(()) -- cgit v1.2.3 From 2e7b88b5256bd6c51226b63b93481a77ac901e14 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 13 Apr 2020 14:39:44 +0200 Subject: Nicer display of projections in Chalk logs --- crates/ra_hir_ty/Cargo.toml | 1 + crates/ra_hir_ty/src/traits/chalk/tls.rs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 59efc1c31..c863112c0 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml @@ -8,6 +8,7 @@ authors = ["rust-analyzer developers"] doctest = false [dependencies] +itertools = "0.9.0" arrayvec = "0.5.1" smallvec = "1.2.0" ena = "0.13.1" diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index 0a8932dae..fa8e4d1ad 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs @@ -2,6 +2,7 @@ use std::fmt; use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; +use itertools::Itertools; use super::{from_chalk, Interner}; use crate::{db::HirDatabase, CallableDef, TypeCtor}; @@ -133,14 +134,15 @@ impl DebugContext<'_> { }; let trait_data = self.0.trait_data(trait_); let params = alias.substitution.parameters(&Interner); - write!( - fmt, - "<{:?} as {}<{:?}>>::{}", - ¶ms[0], - trait_data.name, - ¶ms[1..], - type_alias_data.name - ) + write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?; + if params.len() > 1 { + write!( + fmt, + "<{}>", + ¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))), + )?; + } + write!(fmt, ">::{}", type_alias_data.name) } pub fn debug_ty( -- cgit v1.2.3 From db32a2e4211f9444ef4f10b633e400d27ed2662e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 22:05:46 +0200 Subject: Implement inline associated type bounds Like `Iterator`. This is an unstable feature, but it's used in the standard library e.g. in the definition of Flatten, so we can't get away with not implementing it :) --- crates/ra_hir_ty/src/lower.rs | 28 ++++++++++++++++----- crates/ra_hir_ty/src/tests/traits.rs | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6c7bbc448..21e7baf8b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -8,6 +8,8 @@ use std::iter; use std::sync::Arc; +use smallvec::SmallVec; + use hir_def::{ adt::StructKind, builtin_type::BuiltinType, @@ -596,21 +598,35 @@ fn assoc_type_bindings_from_type_bound<'a>( .into_iter() .flat_map(|segment| segment.args_and_bindings.into_iter()) .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) - .map(move |(name, type_ref)| { + .flat_map(move |binding| { let associated_ty = associated_type_by_name_including_super_traits( ctx.db.upcast(), trait_ref.trait_, - &name, + &binding.name, ); let associated_ty = match associated_ty { - None => return GenericPredicate::Error, + None => return SmallVec::<[GenericPredicate; 1]>::new(), Some(t) => t, }; let projection_ty = ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; - let ty = Ty::from_hir(ctx, type_ref); - let projection_predicate = ProjectionPredicate { projection_ty, ty }; - GenericPredicate::Projection(projection_predicate) + let mut preds = SmallVec::with_capacity( + binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), + ); + if let Some(type_ref) = &binding.type_ref { + let ty = Ty::from_hir(ctx, type_ref); + let projection_predicate = + ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; + preds.push(GenericPredicate::Projection(projection_predicate)); + } + for bound in &binding.bounds { + preds.extend(GenericPredicate::from_type_bound( + ctx, + bound, + Ty::Projection(projection_ty.clone()), + )); + } + preds }) } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..53461bdbb 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1923,6 +1923,53 @@ fn test() where T: Trait, U: Trait { assert_eq!(t, "{unknown}"); } +#[test] +fn inline_assoc_type_bounds_1() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} +trait OtherTrait { + fn foo(&self) -> T; +} + +// workaround for Chalk assoc type normalization problems +pub struct S; +impl Iterator for S { + type Item = ::Item; +} + +fn test>>() { + let x: as Iterator>::Item; + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn inline_assoc_type_bounds_2() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} + +fn test>>() { + let x: <::Item as Iterator>::Item; + x<|>; +} +"#, + ); + // assert_eq!(t, "u32"); + // doesn't currently work, Chalk #234 + assert_eq!(t, "{unknown}"); +} + #[test] fn unify_impl_trait() { assert_snapshot!( -- cgit v1.2.3 From d88d67819b3f052422ad3f024e44ad73dde1630b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 12 Apr 2020 12:29:03 +0200 Subject: Handle `Self::Type` in trait definitions when referring to own associated type It was implemented for other generic parameters for the trait, but not for `Self`. --- crates/ra_hir_ty/src/lower.rs | 14 ++++++++++++-- crates/ra_hir_ty/src/tests/regression.rs | 3 +-- crates/ra_hir_ty/src/tests/traits.rs | 26 +++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6c7bbc448..7b5990a47 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -360,13 +360,23 @@ impl Ty { }, Some(TypeNs::GenericParam(param_id)) => { let predicates = ctx.db.generic_predicates_for_param(param_id); - predicates + let mut traits_: Vec<_> = predicates .iter() .filter_map(|pred| match &pred.value { GenericPredicate::Implemented(tr) => Some(tr.trait_), _ => None, }) - .collect() + .collect(); + // Handle `Self::Type` referring to own associated type in trait definitions + if let GenericDefId::TraitId(trait_id) = param_id.parent { + let generics = generics(ctx.db.upcast(), trait_id.into()); + if generics.params.types[param_id.local_id].provenance + == TypeParamProvenance::TraitSelf + { + traits_.push(trait_id); + } + } + traits_ } _ => return Ty::Unknown, }; diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 3402e0cb5..d69115a2f 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -451,8 +451,7 @@ pub mod str { "#, ); - // should be Option, but currently not because of Chalk ambiguity problem - assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos)); + assert_eq!("(Option, Option)", super::type_at_pos(&db, pos)); } #[test] diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..d088bf309 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1803,7 +1803,7 @@ fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { } #[test] -fn unselected_projection_on_trait_self() { +fn unselected_projection_on_impl_self() { assert_snapshot!(infer( r#" //- /main.rs @@ -1843,6 +1843,30 @@ impl Trait for S2 { "###); } +#[test] +fn unselected_projection_on_trait_self() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; + + fn f(&self) -> Self::Item { loop {} } +} + +struct S; +impl Trait for S { + type Item = u32; +} + +fn test() { + S.f()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + #[test] fn trait_impl_self_ty() { let t = type_at( -- cgit v1.2.3