Skip to content

Commit 99bfdeb

Browse files
committed
Implement consecutive shorthand projections
1 parent 737e423 commit 99bfdeb

13 files changed

+184
-43
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -1070,13 +1070,46 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10701070
)?
10711071
}
10721072
(
1073-
&ty::Param(_),
1074-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
1073+
ty::Param(_),
1074+
Res::SelfTyParam { trait_: param_def_id }
1075+
| Res::Def(DefKind::TyParam, param_def_id),
10751076
) => self.probe_single_ty_param_bound_for_assoc_ty(
1076-
param_did.expect_local(),
1077+
param_def_id.expect_local(),
10771078
assoc_ident,
10781079
span,
10791080
)?,
1081+
// FIXME(fmease):
1082+
// Should we require the unlowered projectee (the HIR QSelf) to be a `Res::Def(DefKind::AssocTy, _)`?
1083+
// Rephrased, should we flat out reject `Identity<T::Assoc>::Assoc` even if `T::Assoc::Assoc` typeck's?
1084+
// For comparison, `Identity<T>::Assoc` gets rejected even if `T::Assoc` passes typeck.
1085+
//
1086+
// If we want to do so, it gets a bit tricky because unfortunately, for type-relative paths,
1087+
// the `Res` never gets updated from `Res::Err` to `Res::Def(AssocTy, _)`.
1088+
//
1089+
// FIXME(fmease): Add UI tests for `feature(more_qualified_paths)` (e.g., `T::A::B { … }`).
1090+
(ty::Alias(ty::Projection, alias_ty), _res) => {
1091+
// FIXME: Double-check that this doesn't lead to any unwanted cycle errors.
1092+
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
1093+
1094+
self.probe_single_bound_for_assoc_item(
1095+
|| {
1096+
let trait_refs = predicates.iter().filter_map(|pred| {
1097+
pred.as_trait_clause().map(|t| t.map_bound(|t| t.trait_ref))
1098+
});
1099+
traits::transitive_bounds_that_define_assoc_item(
1100+
tcx,
1101+
trait_refs,
1102+
assoc_ident,
1103+
)
1104+
},
1105+
qself_ty,
1106+
None,
1107+
ty::AssocKind::Type,
1108+
assoc_ident,
1109+
span,
1110+
None,
1111+
)?
1112+
}
10801113
_ => {
10811114
let reported = if variant_resolution.is_some() {
10821115
// Variant in type position
@@ -1180,6 +1213,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11801213
);
11811214
});
11821215
}
1216+
11831217
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
11841218
}
11851219

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,6 @@ ui/issues/issue-23024.rs
18551855
ui/issues/issue-23036.rs
18561856
ui/issues/issue-23041.rs
18571857
ui/issues/issue-23046.rs
1858-
ui/issues/issue-23073.rs
18591858
ui/issues/issue-2311-2.rs
18601859
ui/issues/issue-2311.rs
18611860
ui/issues/issue-2312.rs

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
1515
const ENTRY_LIMIT: u32 = 900;
1616
// FIXME: The following limits should be reduced eventually.
1717

18-
const ISSUES_ENTRY_LIMIT: u32 = 1672;
18+
const ISSUES_ENTRY_LIMIT: u32 = 1670;
1919

2020
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2121
"rs", // test source files
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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 as HaveItAll>::See as ChooseMe>::Type);
16+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17+
help: use fully-qualified syntax to disambiguate
18+
|
19+
LL | struct Env<T: HaveItAll>(<<T as HaveItAll>::See as PickMe>::Type);
20+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21+
22+
error: aborting due to 1 previous error
23+
24+
For more information about this error, try `rustc --explain E0221`.
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::Product;
70+
71+
chain(());
72+
let _: <() as Chain>::Link::Link::Link;
73+
74+
scope::<(), bool, 32>();
75+
}
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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// FIXME(fmease): Should we allow this as part of this MVP?
2+
// Of course, under #22519 (arbitrary shorthand projections), this should obviously typeck.
3+
// For reference, `T::Alias` typeck'ing does *not* imply `Identity<T>::Alias` typeck'ing.
4+
//@ check-pass
5+
6+
type Identity<T> = T;
7+
8+
trait Trait {
9+
type Project;
10+
}
11+
12+
fn scope<T: Trait>() {
13+
let _: Identity<T>::Project;
14+
}
15+
16+
fn main() {}

tests/ui/issues/issue-23073.stderr

-14
This file was deleted.

tests/ui/qualified/qualified-path-params-2.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Check that qualified paths with type parameters
22
// fail during type checking and not during parsing
3-
43
struct S;
54

65
trait Tr {
@@ -15,7 +14,6 @@ impl S {
1514
fn f<T>() {}
1615
}
1716

18-
type A = <S as Tr>::A::f<u8>;
19-
//~^ ERROR ambiguous associated type
17+
type A = <S as Tr>::A::f<u8>; //~ ERROR associated type `f` not found for `<S as Tr>::A`
2018

2119
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
error[E0223]: ambiguous associated type
2-
--> $DIR/qualified-path-params-2.rs:18:10
1+
error[E0220]: associated type `f` not found for `<S as Tr>::A`
2+
--> $DIR/qualified-path-params-2.rs:17:24
33
|
44
LL | type A = <S as Tr>::A::f<u8>;
5-
| ^^^^^^^^^^^^^^^^^^^
6-
|
7-
help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path
8-
|
9-
LL | type A = <<S as Tr>::A as Example>::f;
10-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5+
| ^ there is a similarly named associated type `A` in the trait `Tr`
116

127
error: aborting due to 1 previous error
138

14-
For more information about this error, try `rustc --explain E0223`.
9+
For more information about this error, try `rustc --explain E0220`.

tests/ui/ufcs/ufcs-partially-resolved.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn main() {
3333
<u8 as Tr>::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr`
3434
<u8 as E>::N::NN; //~ ERROR expected trait, found enum `E`
3535
<u8 as A>::N::NN; //~ ERROR expected trait, found type alias `A`
36-
let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
36+
let _: <u8 as Tr>::Y::NN; //~ ERROR associated type `NN` not found for `<u8 as Tr>::Y`
3737
let _: <u8 as E>::Y::NN; //~ ERROR expected trait, found enum `E`
3838
<u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found for type `u16`
3939
<u8 as E>::Y::NN; //~ ERROR expected trait, found enum `E`

tests/ui/ufcs/ufcs-partially-resolved.stderr

+5-10
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,11 @@ LL | let _: <u8 as Dr>::Z::N;
245245
| |
246246
| help: an associated type with a similar name exists: `X`
247247

248-
error[E0223]: ambiguous associated type
249-
--> $DIR/ufcs-partially-resolved.rs:36:12
248+
error[E0220]: associated type `NN` not found for `<u8 as Tr>::Y`
249+
--> $DIR/ufcs-partially-resolved.rs:36:27
250250
|
251251
LL | let _: <u8 as Tr>::Y::NN;
252-
| ^^^^^^^^^^^^^^^^^
253-
|
254-
help: if there were a trait named `Example` with associated type `NN` implemented for `<u8 as Tr>::Y`, you could use the fully-qualified path
255-
|
256-
LL | let _: <<u8 as Tr>::Y as Example>::NN;
257-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
252+
| ^^ associated type `NN` not found
258253

259254
error[E0599]: no associated item named `NN` found for type `u16` in the current scope
260255
--> $DIR/ufcs-partially-resolved.rs:38:20
@@ -270,5 +265,5 @@ LL | <u8 as Dr>::X::N;
270265

271266
error: aborting due to 32 previous errors
272267

273-
Some errors have detailed explanations: E0223, E0404, E0405, E0575, E0576, E0599.
274-
For more information about an error, try `rustc --explain E0223`.
268+
Some errors have detailed explanations: E0220, E0404, E0405, E0575, E0576, E0599.
269+
For more information about an error, try `rustc --explain E0220`.

0 commit comments

Comments
 (0)