Skip to content

Commit d61909f

Browse files
3964: Nicer Chalk debug logs r=matklad a=flodiebold I'm looking at a lot of Chalk debug logs at the moment, so here's a few changes to make them slightly nicer... 3965: Implement inline associated type bounds r=matklad a=flodiebold Like `Iterator<Item: SomeTrait>`. 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 :) (This is cherry-picked from my recursive solver branch, where it works better, but I did manage to write a test that works with the current Chalk solver as well...) 3967: Handle `Self::Type` in trait definitions when referring to own associated type r=matklad a=flodiebold It was implemented for other generic parameters for the trait, but not for `Self`. (Last one off my recursive solver branch 😄 ) Co-authored-by: Florian Diebold <[email protected]>
4 parents 9726401 + 2e7b88b + db32a2e + d88d678 commit d61909f

File tree

10 files changed

+192
-32
lines changed

10 files changed

+192
-32
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir_def/src/data.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ra_syntax::ast::{
1515
use crate::{
1616
attr::Attrs,
1717
db::DefDatabase,
18-
path::{path, GenericArgs, Path},
18+
path::{path, AssociatedTypeBinding, GenericArgs, Path},
1919
src::HasSource,
2020
type_ref::{Mutability, TypeBound, TypeRef},
2121
visibility::RawVisibility,
@@ -95,7 +95,11 @@ fn desugar_future_path(orig: TypeRef) -> Path {
9595
let path = path![std::future::Future];
9696
let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
9797
let mut last = GenericArgs::empty();
98-
last.bindings.push((name![Output], orig));
98+
last.bindings.push(AssociatedTypeBinding {
99+
name: name![Output],
100+
type_ref: Some(orig),
101+
bounds: Vec::new(),
102+
});
99103
generic_args.push(Some(Arc::new(last)));
100104

101105
Path::from_known_path(path, generic_args)

crates/ra_hir_def/src/path.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ use hir_expand::{
1414
use ra_db::CrateId;
1515
use ra_syntax::ast;
1616

17-
use crate::{type_ref::TypeRef, InFile};
17+
use crate::{
18+
type_ref::{TypeBound, TypeRef},
19+
InFile,
20+
};
1821

1922
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2023
pub struct ModPath {
@@ -111,7 +114,21 @@ pub struct GenericArgs {
111114
/// is left out.
112115
pub has_self_type: bool,
113116
/// Associated type bindings like in `Iterator<Item = T>`.
114-
pub bindings: Vec<(Name, TypeRef)>,
117+
pub bindings: Vec<AssociatedTypeBinding>,
118+
}
119+
120+
/// An associated type binding like in `Iterator<Item = T>`.
121+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122+
pub struct AssociatedTypeBinding {
123+
/// The name of the associated type.
124+
pub name: Name,
125+
/// The type bound to this associated type (in `Item = T`, this would be the
126+
/// `T`). This can be `None` if there are bounds instead.
127+
pub type_ref: Option<TypeRef>,
128+
/// Bounds for the associated type, like in `Iterator<Item:
129+
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
130+
/// feature.)
131+
pub bounds: Vec<TypeBound>,
115132
}
116133

117134
/// A single generic argument.

crates/ra_hir_def/src/path/lower.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ use hir_expand::{
99
hygiene::Hygiene,
1010
name::{name, AsName},
1111
};
12-
use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner};
12+
use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner};
1313

14+
use super::AssociatedTypeBinding;
1415
use crate::{
1516
path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
16-
type_ref::TypeRef,
17+
type_ref::{TypeBound, TypeRef},
1718
};
1819

1920
pub(super) use lower_use::lower_use_tree;
@@ -136,10 +137,16 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs>
136137
// lifetimes ignored for now
137138
let mut bindings = Vec::new();
138139
for assoc_type_arg in node.assoc_type_args() {
140+
let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg;
139141
if let Some(name_ref) = assoc_type_arg.name_ref() {
140142
let name = name_ref.as_name();
141-
let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
142-
bindings.push((name, type_ref));
143+
let type_ref = assoc_type_arg.type_ref().map(TypeRef::from_ast);
144+
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
145+
l.bounds().map(TypeBound::from_ast).collect()
146+
} else {
147+
Vec::new()
148+
};
149+
bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
143150
}
144151
}
145152
if args.is_empty() && bindings.is_empty() {
@@ -168,7 +175,11 @@ fn lower_generic_args_from_fn_path(
168175
}
169176
if let Some(ret_type) = ret_type {
170177
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
171-
bindings.push((name![Output], type_ref))
178+
bindings.push(AssociatedTypeBinding {
179+
name: name![Output],
180+
type_ref: Some(type_ref),
181+
bounds: Vec::new(),
182+
});
172183
}
173184
if args.is_empty() && bindings.is_empty() {
174185
None

crates/ra_hir_def/src/type_ref.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,16 @@ impl TypeRef {
163163
let crate::path::GenericArg::Type(type_ref) = arg;
164164
go(type_ref, f);
165165
}
166-
for (_, type_ref) in &args_and_bindings.bindings {
167-
go(type_ref, f);
166+
for binding in &args_and_bindings.bindings {
167+
if let Some(type_ref) = &binding.type_ref {
168+
go(type_ref, f);
169+
}
170+
for bound in &binding.bounds {
171+
match bound {
172+
TypeBound::Path(path) => go_path(path, f),
173+
TypeBound::Error => (),
174+
}
175+
}
168176
}
169177
}
170178
}

crates/ra_hir_ty/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ authors = ["rust-analyzer developers"]
88
doctest = false
99

1010
[dependencies]
11+
itertools = "0.9.0"
1112
arrayvec = "0.5.1"
1213
smallvec = "1.2.0"
1314
ena = "0.13.1"

crates/ra_hir_ty/src/lower.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use std::iter;
99
use std::sync::Arc;
1010

11+
use smallvec::SmallVec;
12+
1113
use hir_def::{
1214
adt::StructKind,
1315
builtin_type::BuiltinType,
@@ -360,13 +362,23 @@ impl Ty {
360362
},
361363
Some(TypeNs::GenericParam(param_id)) => {
362364
let predicates = ctx.db.generic_predicates_for_param(param_id);
363-
predicates
365+
let mut traits_: Vec<_> = predicates
364366
.iter()
365367
.filter_map(|pred| match &pred.value {
366368
GenericPredicate::Implemented(tr) => Some(tr.trait_),
367369
_ => None,
368370
})
369-
.collect()
371+
.collect();
372+
// Handle `Self::Type` referring to own associated type in trait definitions
373+
if let GenericDefId::TraitId(trait_id) = param_id.parent {
374+
let generics = generics(ctx.db.upcast(), trait_id.into());
375+
if generics.params.types[param_id.local_id].provenance
376+
== TypeParamProvenance::TraitSelf
377+
{
378+
traits_.push(trait_id);
379+
}
380+
}
381+
traits_
370382
}
371383
_ => return Ty::Unknown,
372384
};
@@ -596,21 +608,35 @@ fn assoc_type_bindings_from_type_bound<'a>(
596608
.into_iter()
597609
.flat_map(|segment| segment.args_and_bindings.into_iter())
598610
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
599-
.map(move |(name, type_ref)| {
611+
.flat_map(move |binding| {
600612
let associated_ty = associated_type_by_name_including_super_traits(
601613
ctx.db.upcast(),
602614
trait_ref.trait_,
603-
&name,
615+
&binding.name,
604616
);
605617
let associated_ty = match associated_ty {
606-
None => return GenericPredicate::Error,
618+
None => return SmallVec::<[GenericPredicate; 1]>::new(),
607619
Some(t) => t,
608620
};
609621
let projection_ty =
610622
ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
611-
let ty = Ty::from_hir(ctx, type_ref);
612-
let projection_predicate = ProjectionPredicate { projection_ty, ty };
613-
GenericPredicate::Projection(projection_predicate)
623+
let mut preds = SmallVec::with_capacity(
624+
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
625+
);
626+
if let Some(type_ref) = &binding.type_ref {
627+
let ty = Ty::from_hir(ctx, type_ref);
628+
let projection_predicate =
629+
ProjectionPredicate { projection_ty: projection_ty.clone(), ty };
630+
preds.push(GenericPredicate::Projection(projection_predicate));
631+
}
632+
for bound in &binding.bounds {
633+
preds.extend(GenericPredicate::from_type_bound(
634+
ctx,
635+
bound,
636+
Ty::Projection(projection_ty.clone()),
637+
));
638+
}
639+
preds
614640
})
615641
}
616642

crates/ra_hir_ty/src/tests/regression.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,7 @@ pub mod str {
451451
"#,
452452
);
453453

454-
// should be Option<char>, but currently not because of Chalk ambiguity problem
455-
assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos));
454+
assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
456455
}
457456

458457
#[test]

crates/ra_hir_ty/src/tests/traits.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
18031803
}
18041804

18051805
#[test]
1806-
fn unselected_projection_on_trait_self() {
1806+
fn unselected_projection_on_impl_self() {
18071807
assert_snapshot!(infer(
18081808
r#"
18091809
//- /main.rs
@@ -1843,6 +1843,30 @@ impl Trait for S2 {
18431843
"###);
18441844
}
18451845

1846+
#[test]
1847+
fn unselected_projection_on_trait_self() {
1848+
let t = type_at(
1849+
r#"
1850+
//- /main.rs
1851+
trait Trait {
1852+
type Item;
1853+
1854+
fn f(&self) -> Self::Item { loop {} }
1855+
}
1856+
1857+
struct S;
1858+
impl Trait for S {
1859+
type Item = u32;
1860+
}
1861+
1862+
fn test() {
1863+
S.f()<|>;
1864+
}
1865+
"#,
1866+
);
1867+
assert_eq!(t, "u32");
1868+
}
1869+
18461870
#[test]
18471871
fn trait_impl_self_ty() {
18481872
let t = type_at(
@@ -1923,6 +1947,53 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
19231947
assert_eq!(t, "{unknown}");
19241948
}
19251949

1950+
#[test]
1951+
fn inline_assoc_type_bounds_1() {
1952+
let t = type_at(
1953+
r#"
1954+
//- /main.rs
1955+
trait Iterator {
1956+
type Item;
1957+
}
1958+
trait OtherTrait<T> {
1959+
fn foo(&self) -> T;
1960+
}
1961+
1962+
// workaround for Chalk assoc type normalization problems
1963+
pub struct S<T>;
1964+
impl<T: Iterator> Iterator for S<T> {
1965+
type Item = <T as Iterator>::Item;
1966+
}
1967+
1968+
fn test<I: Iterator<Item: OtherTrait<u32>>>() {
1969+
let x: <S<I> as Iterator>::Item;
1970+
x.foo()<|>;
1971+
}
1972+
"#,
1973+
);
1974+
assert_eq!(t, "u32");
1975+
}
1976+
1977+
#[test]
1978+
fn inline_assoc_type_bounds_2() {
1979+
let t = type_at(
1980+
r#"
1981+
//- /main.rs
1982+
trait Iterator {
1983+
type Item;
1984+
}
1985+
1986+
fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
1987+
let x: <<I as Iterator>::Item as Iterator>::Item;
1988+
x<|>;
1989+
}
1990+
"#,
1991+
);
1992+
// assert_eq!(t, "u32");
1993+
// doesn't currently work, Chalk #234
1994+
assert_eq!(t, "{unknown}");
1995+
}
1996+
19261997
#[test]
19271998
fn unify_impl_trait() {
19281999
assert_snapshot!(

crates/ra_hir_ty/src/traits/chalk/tls.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
use std::fmt;
33

44
use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
5+
use itertools::Itertools;
56

67
use super::{from_chalk, Interner};
78
use crate::{db::HirDatabase, CallableDef, TypeCtor};
8-
use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
9+
use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
910

1011
pub use unsafe_tls::{set_current_program, with_current_program};
1112

@@ -69,7 +70,27 @@ impl DebugContext<'_> {
6970
write!(f, "{}::{}", trait_name, name)?;
7071
}
7172
TypeCtor::Closure { def, expr } => {
72-
write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?;
73+
write!(f, "{{closure {:?} in ", expr.into_raw())?;
74+
match def {
75+
DefWithBodyId::FunctionId(func) => {
76+
write!(f, "fn {}", self.0.function_data(func).name)?
77+
}
78+
DefWithBodyId::StaticId(s) => {
79+
if let Some(name) = self.0.static_data(s).name.as_ref() {
80+
write!(f, "body of static {}", name)?;
81+
} else {
82+
write!(f, "body of unnamed static {:?}", s)?;
83+
}
84+
}
85+
DefWithBodyId::ConstId(c) => {
86+
if let Some(name) = self.0.const_data(c).name.as_ref() {
87+
write!(f, "body of const {}", name)?;
88+
} else {
89+
write!(f, "body of unnamed const {:?}", c)?;
90+
}
91+
}
92+
};
93+
write!(f, "}}")?;
7394
}
7495
}
7596
Ok(())
@@ -113,14 +134,15 @@ impl DebugContext<'_> {
113134
};
114135
let trait_data = self.0.trait_data(trait_);
115136
let params = alias.substitution.parameters(&Interner);
116-
write!(
117-
fmt,
118-
"<{:?} as {}<{:?}>>::{}",
119-
&params[0],
120-
trait_data.name,
121-
&params[1..],
122-
type_alias_data.name
123-
)
137+
write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
138+
if params.len() > 1 {
139+
write!(
140+
fmt,
141+
"<{}>",
142+
&params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
143+
)?;
144+
}
145+
write!(fmt, ">::{}", type_alias_data.name)
124146
}
125147

126148
pub fn debug_ty(

0 commit comments

Comments
 (0)