Skip to content

Commit cc471ea

Browse files
committed
Implement consecutive shorthand projections
1 parent 21cf7fb commit cc471ea

18 files changed

Lines changed: 270 additions & 52 deletions

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
118118
pub(super) fn report_unresolved_assoc_item<I>(
119119
&self,
120120
all_candidates: impl Fn() -> I,
121-
qself: AssocItemQSelf,
121+
qself: AssocItemQSelf<'tcx>,
122122
assoc_tag: ty::AssocTag,
123123
assoc_ident: Ident,
124124
span: Span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,18 +236,20 @@ pub trait HirTyLowerer<'tcx> {
236236
/// The "qualified self" of an associated item path.
237237
///
238238
/// For diagnostic purposes only.
239-
enum AssocItemQSelf {
239+
enum AssocItemQSelf<'tcx> {
240240
Trait(DefId),
241241
TyParam(LocalDefId, Span),
242242
SelfTyAlias,
243+
AssocTy(Ty<'tcx>),
243244
}
244245

245-
impl AssocItemQSelf {
246-
fn to_string(&self, tcx: TyCtxt<'_>) -> String {
246+
impl<'tcx> AssocItemQSelf<'tcx> {
247+
fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
247248
match *self {
248249
Self::Trait(def_id) => tcx.def_path_str(def_id),
249250
Self::TyParam(def_id, _) => tcx.hir_ty_param_name(def_id).to_string(),
250251
Self::SelfTyAlias => kw::SelfUpper.to_string(),
252+
Self::AssocTy(ty) => ty.to_string(),
251253
}
252254
}
253255
}
@@ -1091,7 +1093,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10911093
fn probe_single_bound_for_assoc_item<I>(
10921094
&self,
10931095
all_candidates: impl Fn() -> I,
1094-
qself: AssocItemQSelf,
1096+
qself: AssocItemQSelf<'tcx>,
10951097
assoc_tag: ty::AssocTag,
10961098
assoc_ident: Ident,
10971099
span: Span,
@@ -1442,15 +1444,45 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14421444
)?
14431445
}
14441446
(
1445-
&ty::Param(_),
1446-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
1447+
ty::Param(_),
1448+
Res::SelfTyParam { trait_: param_def_id }
1449+
| Res::Def(DefKind::TyParam, param_def_id),
14471450
) => self.probe_single_ty_param_bound_for_assoc_item(
1448-
param_did.expect_local(),
1451+
param_def_id.expect_local(),
14491452
hir_self_ty.span,
14501453
assoc_tag,
14511454
segment.ident,
14521455
span,
14531456
)?,
1457+
// FIXME(fmease):
1458+
// Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased,
1459+
// `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity<T::Assoc>::Assoc` typeck'ing where
1460+
// `Identity` is an eager (i.e., non-lazy) type alias. We should do this
1461+
// * for consistency with lazy type aliases (`ty::Weak`)
1462+
// * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity<T>::Assoc`
1463+
// typeck'ing
1464+
(ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => {
1465+
// FIXME: Utilizing `item_bounds` for this is cycle-prone.
1466+
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
1467+
1468+
self.probe_single_bound_for_assoc_item(
1469+
|| {
1470+
let trait_refs = predicates.iter().filter_map(|pred| {
1471+
pred.as_trait_clause().map(|t| t.map_bound(|t| t.trait_ref))
1472+
});
1473+
traits::transitive_bounds_that_define_assoc_item(
1474+
tcx,
1475+
trait_refs,
1476+
segment.ident,
1477+
)
1478+
},
1479+
AssocItemQSelf::AssocTy(self_ty),
1480+
assoc_tag,
1481+
segment.ident,
1482+
span,
1483+
None,
1484+
)?
1485+
}
14541486
_ => {
14551487
return Err(self.report_unresolved_type_relative_path(
14561488
self_ty,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait ChooseMe {
2+
type Type;
3+
}
4+
5+
trait PickMe {
6+
type Type;
7+
}
8+
9+
trait HaveItAll {
10+
type See: ChooseMe + PickMe;
11+
}
12+
13+
struct Env<T: HaveItAll>(T::See::Type);
14+
//~^ ERROR ambiguous associated type `Type` in bounds of `<T as HaveItAll>::See`
15+
16+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0221]: ambiguous associated type `Type` in bounds of `<T as HaveItAll>::See`
2+
--> $DIR/consecutive-shorthand-projections-ambiguous.rs:13:26
3+
|
4+
LL | type Type;
5+
| --------- ambiguous `Type` from `ChooseMe`
6+
...
7+
LL | type Type;
8+
| --------- ambiguous `Type` from `PickMe`
9+
...
10+
LL | struct Env<T: HaveItAll>(T::See::Type);
11+
| ^^^^^^^^^^^^ ambiguous associated type `Type`
12+
|
13+
help: use fully-qualified syntax to disambiguate
14+
|
15+
LL - struct Env<T: HaveItAll>(T::See::Type);
16+
LL + struct Env<T: HaveItAll>(<<T as HaveItAll>::See as ChooseMe>::Type);
17+
|
18+
help: use fully-qualified syntax to disambiguate
19+
|
20+
LL - struct Env<T: HaveItAll>(T::See::Type);
21+
LL + struct Env<T: HaveItAll>(<<T as HaveItAll>::See as PickMe>::Type);
22+
|
23+
24+
error: aborting due to 1 previous error
25+
26+
For more information about this error, try `rustc --explain E0221`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// FIXME: Description
2+
3+
fn parametrized<T: Trait<Ty: Trait>>() {
4+
let _: T::Ty::Ty; //~ ERROR associated type `Ty` not found for `<T as Trait>::Ty`
5+
}
6+
7+
trait Trait {
8+
type Ty;
9+
}
10+
11+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0220]: associated type `Ty` not found for `<T as Trait>::Ty`
2+
--> $DIR/consecutive-shorthand-projections-not-in-item-bounds.rs:4:19
3+
|
4+
LL | let _: T::Ty::Ty;
5+
| ^^ there is an associated type `Ty` in the trait `Trait`
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0220`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
3+
fn make<T: Indir0<Ty: Indir1<Ty = Struct>>>() {
4+
let _ = T::Ty::Ty { field: 0 };
5+
}
6+
7+
trait Indir0 {
8+
type Ty: Indir1;
9+
}
10+
11+
trait Indir1 {
12+
type Ty;
13+
}
14+
15+
struct Struct {
16+
field: i32
17+
}
18+
19+
fn main() {}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//@ check-pass
2+
3+
fn factory0<T: Factory>() {
4+
let _: T::Output::Category;
5+
}
6+
7+
fn factory1<T: Factory<Output: Product<Category = u16>>>(category: u16) {
8+
let _: T::Output::Category = category;
9+
}
10+
11+
fn factory2<T: Factory>(_: T::Output::Category) {}
12+
13+
trait Factory {
14+
type Output: Product;
15+
}
16+
17+
impl Factory for () {
18+
type Output = u128;
19+
}
20+
21+
trait Product {
22+
type Category;
23+
}
24+
25+
impl Product for u128 {
26+
type Category = u16;
27+
}
28+
29+
/////////////////////////
30+
31+
fn chain<C: Chain<Link = C>>(chain: C) {
32+
let _: C::Link::Link::Link::Link::Link = chain;
33+
}
34+
35+
trait Chain { type Link: Chain; }
36+
37+
impl Chain for () {
38+
type Link = Self;
39+
}
40+
41+
/////////////////////////
42+
43+
fn scope<'r, T: Main<'static, (i32, U), 1>, U, const Q: usize>() {
44+
let _: T::Next<'r, (), Q>::Final;
45+
}
46+
47+
trait Main<'a, T, const N: usize> {
48+
type Next<'b, U, const M: usize>: Aux<'a, 'b, (T, U), N, M>;
49+
}
50+
51+
impl<'a, T, const N: usize> Main<'a, T, N> for () {
52+
type Next<'_b, _U, const _M: usize> = ();
53+
}
54+
55+
trait Aux<'a, 'b, T, const N: usize, const M: usize> {
56+
type Final;
57+
}
58+
59+
impl<'a, 'b, T, const N: usize, const M: usize> Aux<'a, 'b, T, N, M> for () {
60+
type Final = [[(T, &'a (), &'b ()); N]; M];
61+
}
62+
63+
/////////////////////////
64+
65+
fn main() {
66+
factory0::<()>();
67+
factory1::<()>(360);
68+
factory2::<()>(720);
69+
let _: <() as Factory>::Output::Category;
70+
71+
chain(());
72+
let _: <() as Chain>::Link::Link::Link;
73+
74+
scope::<(), bool, 32>();
75+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
//@ check-pass
2+
13
#![feature(associated_type_defaults)]
24

35
trait Foo { type T; }
6+
47
trait Bar {
58
type Foo: Foo;
6-
type FooT = <<Self as Bar>::Foo>::T; //~ ERROR ambiguous associated type
9+
type FooT = <<Self as Bar>::Foo>::T;
710
}
811

912
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0223]: ambiguous associated type
2+
--> $DIR/non-consecutive-shorthand-projections.rs:16:12
3+
|
4+
LL | let _: Identity<T::Project>::Project;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: if there were a trait named `Example` with associated type `Project` implemented for `Identity<<T as Trait>::Project>`, you could use the fully-qualified path
8+
|
9+
LL - let _: Identity<T::Project>::Project;
10+
LL + let _: <Identity<<T as Trait>::Project> as Example>::Project;
11+
|
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0223`.

0 commit comments

Comments
 (0)