Skip to content

Commit cfed918

Browse files
committed
Auto merge of #79266 - b-naber:gat_trait_path_parser, r=petrochenkov
Generic Associated Types in Trait Paths - Ast part The Ast part of #78978 r? `@petrochenkov`
2 parents cb56a44 + 5c4568d commit cfed918

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+447
-60
lines changed

compiler/rustc_ast/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,7 @@ impl UintTy {
18451845
pub struct AssocTyConstraint {
18461846
pub id: NodeId,
18471847
pub ident: Ident,
1848+
pub gen_args: Option<GenericArgs>,
18481849
pub kind: AssocTyConstraintKind,
18491850
pub span: Span,
18501851
}

compiler/rustc_ast/src/mut_visit.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -441,11 +441,14 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
441441
}
442442

443443
pub fn noop_visit_ty_constraint<T: MutVisitor>(
444-
AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
444+
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
445445
vis: &mut T,
446446
) {
447447
vis.visit_id(id);
448448
vis.visit_ident(ident);
449+
if let Some(ref mut gen_args) = gen_args {
450+
vis.visit_generic_args(gen_args);
451+
}
449452
match kind {
450453
AssocTyConstraintKind::Equality { ref mut ty } => {
451454
vis.visit_ty(ty);

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
485485
constraint: &'a AssocTyConstraint,
486486
) {
487487
visitor.visit_ident(constraint.ident);
488+
if let Some(ref gen_args) = constraint.gen_args {
489+
visitor.visit_generic_args(gen_args.span(), gen_args);
490+
}
488491
match constraint.kind {
489492
AssocTyConstraintKind::Equality { ref ty } => {
490493
visitor.visit_ty(ty);

compiler/rustc_ast_lowering/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10001000
) -> hir::TypeBinding<'hir> {
10011001
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
10021002

1003+
if let Some(ref gen_args) = constraint.gen_args {
1004+
self.sess.span_fatal(
1005+
gen_args.span(),
1006+
"generic associated types in trait paths are currently not implemented",
1007+
);
1008+
}
1009+
10031010
let kind = match constraint.kind {
10041011
AssocTyConstraintKind::Equality { ref ty } => {
10051012
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }

compiler/rustc_ast_passes/src/ast_validation.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1372,16 +1372,18 @@ fn deny_equality_constraints(
13721372
if param.ident == *ident {
13731373
let param = ident;
13741374
match &full_path.segments[qself.position..] {
1375-
[PathSegment { ident, .. }] => {
1375+
[PathSegment { ident, args, .. }] => {
13761376
// Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
13771377
let mut assoc_path = full_path.clone();
13781378
// Remove `Bar` from `Foo::Bar`.
13791379
assoc_path.segments.pop();
13801380
let len = assoc_path.segments.len() - 1;
1381+
let gen_args = args.as_ref().map(|p| (**p).clone());
13811382
// Build `<Bar = RhsTy>`.
13821383
let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
13831384
id: rustc_ast::node_id::DUMMY_NODE_ID,
13841385
ident: *ident,
1386+
gen_args,
13851387
kind: AssocTyConstraintKind::Equality {
13861388
ty: predicate.rhs_ty.clone(),
13871389
},

compiler/rustc_parse/src/parser/path.rs

+83-26
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ use super::{Parser, TokenType};
33
use crate::maybe_whole;
44
use rustc_ast::ptr::P;
55
use rustc_ast::token::{self, Token};
6-
use rustc_ast::{
7-
self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs,
8-
};
6+
use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
97
use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
8+
use rustc_ast::{GenericArg, GenericArgs};
109
use rustc_ast::{Path, PathSegment, QSelf};
1110
use rustc_errors::{pluralize, Applicability, PResult};
1211
use rustc_span::source_map::{BytePos, Span};
@@ -414,32 +413,40 @@ impl<'a> Parser<'a> {
414413

415414
/// Parses a single argument in the angle arguments `<...>` of a path segment.
416415
fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
417-
if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
418-
{
419-
// Parse associated type constraint.
420-
let lo = self.token.span;
421-
let ident = self.parse_ident()?;
422-
let kind = if self.eat(&token::Eq) {
423-
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
424-
AssocTyConstraintKind::Equality { ty }
425-
} else if self.eat(&token::Colon) {
426-
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
427-
AssocTyConstraintKind::Bound { bounds }
428-
} else {
429-
unreachable!();
430-
};
416+
let lo = self.token.span;
417+
let arg = self.parse_generic_arg()?;
418+
match arg {
419+
Some(arg) => {
420+
if self.check(&token::Colon) | self.check(&token::Eq) {
421+
let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
422+
let kind = if self.eat(&token::Colon) {
423+
// Parse associated type constraint bound.
424+
425+
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
426+
AssocTyConstraintKind::Bound { bounds }
427+
} else if self.eat(&token::Eq) {
428+
// Parse associated type equality constraint
429+
430+
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
431+
AssocTyConstraintKind::Equality { ty }
432+
} else {
433+
unreachable!();
434+
};
431435

432-
let span = lo.to(self.prev_token.span);
436+
let span = lo.to(self.prev_token.span);
433437

434-
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
435-
if let AssocTyConstraintKind::Bound { .. } = kind {
436-
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
438+
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
439+
if let AssocTyConstraintKind::Bound { .. } = kind {
440+
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
441+
}
442+
let constraint =
443+
AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
444+
Ok(Some(AngleBracketedArg::Constraint(constraint)))
445+
} else {
446+
Ok(Some(AngleBracketedArg::Arg(arg)))
447+
}
437448
}
438-
439-
let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
440-
Ok(Some(AngleBracketedArg::Constraint(constraint)))
441-
} else {
442-
Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
449+
_ => Ok(None),
443450
}
444451
}
445452

@@ -542,4 +549,54 @@ impl<'a> Parser<'a> {
542549
};
543550
Ok(Some(arg))
544551
}
552+
553+
fn get_ident_from_generic_arg(
554+
&self,
555+
gen_arg: GenericArg,
556+
lo: Span,
557+
) -> PResult<'a, (Ident, Option<GenericArgs>)> {
558+
let gen_arg_span = gen_arg.span();
559+
match gen_arg {
560+
GenericArg::Type(t) => match t.into_inner().kind {
561+
ast::TyKind::Path(qself, mut path) => {
562+
if let Some(qself) = qself {
563+
let mut err = self.struct_span_err(
564+
gen_arg_span,
565+
"qualified paths cannot be used in associated type constraints",
566+
);
567+
err.span_label(
568+
qself.path_span,
569+
"not allowed in associated type constraints",
570+
);
571+
return Err(err);
572+
}
573+
if path.segments.len() == 1 {
574+
let path_seg = path.segments.remove(0);
575+
let ident = path_seg.ident;
576+
let gen_args = path_seg.args.map(|args| args.into_inner());
577+
return Ok((ident, gen_args));
578+
}
579+
let err = self.struct_span_err(
580+
path.span,
581+
"paths with multiple segments cannot be used in associated type constraints",
582+
);
583+
return Err(err);
584+
}
585+
_ => {
586+
let span = lo.to(self.prev_token.span);
587+
let err = self.struct_span_err(
588+
span,
589+
"only path types can be used in associated type constraints",
590+
);
591+
return Err(err);
592+
}
593+
},
594+
_ => {
595+
let span = lo.to(self.prev_token.span);
596+
let err = self
597+
.struct_span_err(span, "only types can be used in associated type constraints");
598+
return Err(err);
599+
}
600+
}
601+
}
545602
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(generic_associated_types)]
2+
//~^ WARNING: the feature `generic_associated_types` is incomplete
3+
4+
trait X {
5+
type Y<'a>;
6+
}
7+
8+
fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
9+
//~^ ERROR: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
2+
--> $DIR/trait-path-expected-token.rs:8:33
3+
|
4+
LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
5+
| ^ expected one of 7 possible tokens
6+
7+
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
8+
--> $DIR/trait-path-expected-token.rs:1:12
9+
|
10+
LL | #![feature(generic_associated_types)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^
12+
|
13+
= note: `#[warn(incomplete_features)]` on by default
14+
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
15+
16+
error: aborting due to previous error; 1 warning emitted
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(generic_associated_types)]
2+
//~^ WARNING: the feature `generic_associated_types` is incomplete
3+
4+
mod error1 {
5+
trait X {
6+
type Y<'a>;
7+
}
8+
9+
fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
10+
//~^ ERROR: expected expression, found `)`
11+
}
12+
13+
mod error2 {
14+
15+
trait X {
16+
type Y<'a>;
17+
}
18+
19+
fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
20+
//~^ ERROR: only types can be used in associated type constraints
21+
}
22+
23+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: expected expression, found `)`
2+
--> $DIR/trait-path-expressions.rs:9:39
3+
|
4+
LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
5+
| - ^ expected expression
6+
| |
7+
| while parsing a const generic argument starting here
8+
9+
error: only types can be used in associated type constraints
10+
--> $DIR/trait-path-expressions.rs:19:30
11+
|
12+
LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
13+
| ^^^^^
14+
15+
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
16+
--> $DIR/trait-path-expressions.rs:1:12
17+
|
18+
LL | #![feature(generic_associated_types)]
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^
20+
|
21+
= note: `#[warn(incomplete_features)]` on by default
22+
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
23+
24+
error: aborting due to 2 previous errors; 1 warning emitted
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(generic_associated_types)]
2+
//~^ WARNING: the feature `generic_associated_types` is incomplete
3+
4+
trait X {
5+
type Y<'a>;
6+
}
7+
8+
const _: () = {
9+
fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
10+
//~^ ERROR: expected one of `>`, const, lifetime, or type, found `:`
11+
//~| ERROR: expected parameter name, found `>`
12+
//~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
13+
//~| ERROR: constant provided when a type was expected
14+
};
15+
16+
const _: () = {
17+
fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
18+
//~^ ERROR: expected one of `>`, const, lifetime, or type, found `=`
19+
};
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error: expected one of `>`, const, lifetime, or type, found `:`
2+
--> $DIR/trait-path-missing-gen_arg.rs:9:30
3+
|
4+
LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
5+
| ^ expected one of `>`, const, lifetime, or type
6+
|
7+
help: expressions must be enclosed in braces to be used as const generic arguments
8+
|
9+
LL | fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {}
10+
| ^ ^
11+
12+
error: expected parameter name, found `>`
13+
--> $DIR/trait-path-missing-gen_arg.rs:9:36
14+
|
15+
LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
16+
| ^ expected parameter name
17+
18+
error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
19+
--> $DIR/trait-path-missing-gen_arg.rs:9:36
20+
|
21+
LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
22+
| ^
23+
| |
24+
| expected one of `!`, `)`, `+`, `,`, or `::`
25+
| help: missing `,`
26+
27+
error: expected one of `>`, const, lifetime, or type, found `=`
28+
--> $DIR/trait-path-missing-gen_arg.rs:17:30
29+
|
30+
LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
31+
| ^ expected one of `>`, const, lifetime, or type
32+
33+
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
34+
--> $DIR/trait-path-missing-gen_arg.rs:1:12
35+
|
36+
LL | #![feature(generic_associated_types)]
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= note: `#[warn(incomplete_features)]` on by default
40+
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
41+
42+
error[E0747]: constant provided when a type was expected
43+
--> $DIR/trait-path-missing-gen_arg.rs:9:23
44+
|
45+
LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
46+
| ^^^^^^^^^^^
47+
48+
error: aborting due to 5 previous errors; 1 warning emitted
49+
50+
For more information about this error, try `rustc --explain E0747`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![feature(generic_associated_types)]
2+
//~^ WARNING: the feature `generic_associated_types` is incomplete
3+
4+
const _: () = {
5+
trait X {
6+
type Y<'a>;
7+
}
8+
9+
fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
10+
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints
11+
};
12+
13+
const _: () = {
14+
trait X {
15+
type Y<'a>;
16+
}
17+
18+
trait Z {}
19+
20+
impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
21+
//~^ ERROR: qualified paths cannot be used in associated type constraints
22+
};
23+
24+
const _: () = {
25+
trait X {
26+
type Y<'a>;
27+
}
28+
29+
trait Z {}
30+
31+
impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
32+
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints
33+
};
34+
35+
fn main() {}

0 commit comments

Comments
 (0)