diff options
44 files changed, 532 insertions, 63 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 328086af183..92b58782465 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1845,6 +1845,7 @@ impl UintTy { pub struct AssocTyConstraint { pub id: NodeId, pub ident: Ident, + pub gen_args: Option<GenericArgs>, pub kind: AssocTyConstraintKind, pub span: Span, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index ddae0ab03e4..878196a6933 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -441,11 +441,14 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[ } pub fn noop_visit_ty_constraint<T: MutVisitor>( - AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint, + AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint, vis: &mut T, ) { vis.visit_id(id); vis.visit_ident(ident); + if let Some(ref mut gen_args) = gen_args { + vis.visit_generic_args(gen_args); + } match kind { AssocTyConstraintKind::Equality { ref mut ty } => { vis.visit_ty(ty); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 560064182e1..60ff956bd96 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -485,6 +485,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocTyConstraint, ) { visitor.visit_ident(constraint.ident); + if let Some(ref gen_args) = constraint.gen_args { + visitor.visit_generic_args(gen_args.span(), gen_args); + } match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { visitor.visit_ty(ty); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f7c693cc94d..eb45a0e1c05 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1000,6 +1000,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); + if let Some(ref gen_args) = constraint.gen_args { + self.sess.span_fatal( + gen_args.span(), + "generic associated types in trait paths are currently not implemented", + ); + } + let kind = match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 08ebcbf381a..4ec3e39facc 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1372,16 +1372,18 @@ fn deny_equality_constraints( if param.ident == *ident { let param = ident; match &full_path.segments[qself.position..] { - [PathSegment { ident, .. }] => { + [PathSegment { ident, args, .. }] => { // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`. let mut assoc_path = full_path.clone(); // Remove `Bar` from `Foo::Bar`. assoc_path.segments.pop(); let len = assoc_path.segments.len() - 1; + let gen_args = args.as_ref().map(|p| (**p).clone()); // Build `<Bar = RhsTy>`. let arg = AngleBracketedArg::Constraint(AssocTyConstraint { id: rustc_ast::node_id::DUMMY_NODE_ID, ident: *ident, + gen_args, kind: AssocTyConstraintKind::Equality { ty: predicate.rhs_ty.clone(), }, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 8a6b0230023..9953d3255b7 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -9,12 +9,14 @@ use rustc_ast as ast; use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP}; use smallvec::SmallVec; +use std::cell::RefCell; use std::mem; use std::path::Path; use std::str; @@ -281,6 +283,25 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke } }; + // Caches the stringification of 'good' `TokenStreams` which passed + // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid + // repeatedly stringifying and comparing the same `TokenStream` for deeply + // nested nonterminals. + // + // We cache by the strinification instead of the `TokenStream` to avoid + // needing to implement `Hash` for `TokenStream`. Note that it's possible to + // have two distinct `TokenStream`s that stringify to the same result + // (e.g. if they differ only in hygiene information). However, any + // information lost during the stringification process is also intentionally + // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine + // that a single cache entry may 'map' to multiple distinct `TokenStream`s. + // + // This is a temporary hack to prevent compilation blowup on certain inputs. + // The entire pretty-print/retokenize process will be removed soon. + thread_local! { + static GOOD_TOKEN_CACHE: RefCell<FxHashSet<String>> = Default::default(); + } + // FIXME(#43081): Avoid this pretty-print + reparse hack // Pretty-print the AST struct without inserting any parenthesis // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`). @@ -288,7 +309,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // ever used for a comparison against the capture tokenstream. let source = pprust::nonterminal_to_string_no_extra_parens(nt); let filename = FileName::macro_expansion_source_code(&source); - let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); + let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span)); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -314,8 +335,13 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { + if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) { + return tokens; + } + // Compare with a non-relaxed delim match to start. if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) { + GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone())); return tokens; } @@ -324,6 +350,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // token stream to match up with inserted parenthesis in the reparsed stream. let source_with_parens = pprust::nonterminal_to_string(nt); let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens); + + if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) { + return tokens; + } + let reparsed_tokens_with_parens = parse_stream_from_source_str( filename_with_parens, source_with_parens, @@ -339,6 +370,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke sess, true, ) { + GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone())); return tokens; } @@ -418,9 +450,9 @@ pub fn tokenstream_probably_equal_for_proc_macro( // to iterate breaking tokens mutliple times. For example: // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' let mut token_trees: SmallVec<[_; 2]>; - if let TokenTree::Token(token) = &tree { + if let TokenTree::Token(token) = tree { let mut out = SmallVec::<[_; 2]>::new(); - out.push(token.clone()); + out.push(token); // Iterate to fixpoint: // * We start off with 'out' containing our initial token, and `temp` empty // * If we are able to break any tokens in `out`, then `out` will have diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index d64fd59b0a6..17e5bcf7605 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -3,10 +3,9 @@ use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; -use rustc_ast::{ - self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs, -}; +use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs}; use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; +use rustc_ast::{GenericArg, GenericArgs}; use rustc_ast::{Path, PathSegment, QSelf}; use rustc_errors::{pluralize, Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -414,32 +413,40 @@ impl<'a> Parser<'a> { /// Parses a single argument in the angle arguments `<...>` of a path segment. fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> { - if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon)) - { - // Parse associated type constraint. - let lo = self.token.span; - let ident = self.parse_ident()?; - let kind = if self.eat(&token::Eq) { - let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; - AssocTyConstraintKind::Equality { ty } - } else if self.eat(&token::Colon) { - let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; - AssocTyConstraintKind::Bound { bounds } - } else { - unreachable!(); - }; + let lo = self.token.span; + let arg = self.parse_generic_arg()?; + match arg { + Some(arg) => { + if self.check(&token::Colon) | self.check(&token::Eq) { + let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?; + let kind = if self.eat(&token::Colon) { + // Parse associated type constraint bound. + + let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; + AssocTyConstraintKind::Bound { bounds } + } else if self.eat(&token::Eq) { + // Parse associated type equality constraint + + let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; + AssocTyConstraintKind::Equality { ty } + } else { + unreachable!(); + }; - let span = lo.to(self.prev_token.span); + let span = lo.to(self.prev_token.span); - // Gate associated type bounds, e.g., `Iterator<Item: Ord>`. - if let AssocTyConstraintKind::Bound { .. } = kind { - self.sess.gated_spans.gate(sym::associated_type_bounds, span); + // Gate associated type bounds, e.g., `Iterator<Item: Ord>`. + if let AssocTyConstraintKind::Bound { .. } = kind { + self.sess.gated_spans.gate(sym::associated_type_bounds, span); + } + let constraint = + AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; + Ok(Some(AngleBracketedArg::Constraint(constraint))) + } else { + Ok(Some(AngleBracketedArg::Arg(arg))) + } } - - let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span }; - Ok(Some(AngleBracketedArg::Constraint(constraint))) - } else { - Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg)) + _ => Ok(None), } } @@ -542,4 +549,54 @@ impl<'a> Parser<'a> { }; Ok(Some(arg)) } + + fn get_ident_from_generic_arg( + &self, + gen_arg: GenericArg, + lo: Span, + ) -> PResult<'a, (Ident, Option<GenericArgs>)> { + let gen_arg_span = gen_arg.span(); + match gen_arg { + GenericArg::Type(t) => match t.into_inner().kind { + ast::TyKind::Path(qself, mut path) => { + if let Some(qself) = qself { + let mut err = self.struct_span_err( + gen_arg_span, + "qualified paths cannot be used in associated type constraints", + ); + err.span_label( + qself.path_span, + "not allowed in associated type constraints", + ); + return Err(err); + } + if path.segments.len() == 1 { + let path_seg = path.segments.remove(0); + let ident = path_seg.ident; + let gen_args = path_seg.args.map(|args| args.into_inner()); + return Ok((ident, gen_args)); + } + let err = self.struct_span_err( + path.span, + "paths with multiple segments cannot be used in associated type constraints", + ); + return Err(err); + } + _ => { + let span = lo.to(self.prev_token.span); + let err = self.struct_span_err( + span, + "only path types can be used in associated type constraints", + ); + return Err(err); + } + }, + _ => { + let span = lo.to(self.prev_token.span); + let err = self + .struct_span_err(span, "only types can be used in associated type constraints"); + return Err(err); + } + } + } } diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs new file mode 100644 index 00000000000..b10bfea9feb --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs @@ -0,0 +1,11 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {} + //~^ ERROR: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr new file mode 100644 index 00000000000..051253cadc6 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr @@ -0,0 +1,17 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` + --> $DIR/trait-path-expected-token.rs:8:33 + | +LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {} + | ^ expected one of 7 possible tokens + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-expected-token.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs new file mode 100644 index 00000000000..de61cfa1cf7 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +mod error1 { + trait X { + type Y<'a>; + } + + fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {} + //~^ ERROR: expected expression, found `)` +} + +mod error2 { + + trait X { + type Y<'a>; + } + + fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} + //~^ ERROR: only types can be used in associated type constraints +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr new file mode 100644 index 00000000000..a9ba8adcaba --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr @@ -0,0 +1,25 @@ +error: expected expression, found `)` + --> $DIR/trait-path-expressions.rs:9:39 + | +LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {} + | - ^ expected expression + | | + | while parsing a const generic argument starting here + +error: only types can be used in associated type constraints + --> $DIR/trait-path-expressions.rs:19:30 + | +LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} + | ^^^^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-expressions.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs new file mode 100644 index 00000000000..dad8c2a2909 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs @@ -0,0 +1,21 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +const _: () = { + fn f1<'a>(arg : Box<dyn X< : 32 >>) {} + //~^ ERROR: expected one of `>`, const, lifetime, or type, found `:` + //~| ERROR: expected parameter name, found `>` + //~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` + //~| ERROR: constant provided when a type was expected +}; + +const _: () = { + fn f1<'a>(arg : Box<dyn X< = 32 >>) {} + //~^ ERROR: expected one of `>`, const, lifetime, or type, found `=` +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr new file mode 100644 index 00000000000..583697f0b67 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -0,0 +1,50 @@ +error: expected one of `>`, const, lifetime, or type, found `:` + --> $DIR/trait-path-missing-gen_arg.rs:9:30 + | +LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {} + | ^ expected one of `>`, const, lifetime, or type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {} + | ^ ^ + +error: expected parameter name, found `>` + --> $DIR/trait-path-missing-gen_arg.rs:9:36 + | +LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {} + | ^ expected parameter name + +error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` + --> $DIR/trait-path-missing-gen_arg.rs:9:36 + | +LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {} + | ^ + | | + | expected one of `!`, `)`, `+`, `,`, or `::` + | help: missing `,` + +error: expected one of `>`, const, lifetime, or type, found `=` + --> $DIR/trait-path-missing-gen_arg.rs:17:30 + | +LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {} + | ^ expected one of `>`, const, lifetime, or type + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-missing-gen_arg.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information + +error[E0747]: constant provided when a type was expected + --> $DIR/trait-path-missing-gen_arg.rs:9:23 + | +LL | fn f1<'a>(arg : Box<dyn X< : 32 >>) {} + | ^^^^^^^^^^^ + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs new file mode 100644 index 00000000000..0bf48b1f418 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs @@ -0,0 +1,35 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +const _: () = { + trait X { + type Y<'a>; + } + + fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints + }; + +const _: () = { + trait X { + type Y<'a>; + } + + trait Z {} + + impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} + //~^ ERROR: qualified paths cannot be used in associated type constraints +}; + +const _: () = { + trait X { + type Y<'a>; + } + + trait Z {} + + impl<T : X<X::Y<'a> = &'a u32>> Z for T {} + //~^ ERROR: paths with multiple segments cannot be used in associated type constraints +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr new file mode 100644 index 00000000000..4e2b84d0182 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr @@ -0,0 +1,31 @@ +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:9:31 + | +LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} + | ^^^^ + +error: qualified paths cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:20:16 + | +LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} + | ^^^^^^^^^-^^^^^^^^ + | | + | not allowed in associated type constraints + +error: paths with multiple segments cannot be used in associated type constraints + --> $DIR/trait-path-segments.rs:31:16 + | +LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {} + | ^^^^^^^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-segments.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs new file mode 100644 index 00000000000..e203a5e0d2d --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs @@ -0,0 +1,10 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +const _: () = { + fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} + //~^ ERROR: generic associated types in trait paths are currently not implemented +}; diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr new file mode 100644 index 00000000000..e59a72a99ee --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -0,0 +1,8 @@ +error: generic associated types in trait paths are currently not implemented + --> $DIR/trait-path-type-error-once-implemented.rs:8:30 + | +LL | fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} + | ^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs new file mode 100644 index 00000000000..6cdb501ec65 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] +//~^ WARNING: the feature `generic_associated_types` is incomplete + +trait X { + type Y<'a>; +} + +const _: () = { + fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} + //~^ ERROR: only path types can be used in associated type constraints +}; + +const _: () = { + fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} + //~^ ERROR: only path types can be used in associated type constraints +}; + +const _: () = { + fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} + //~^ ERROR: only types can be used in associated type constraints +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr new file mode 100644 index 00000000000..f5be084613b --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr @@ -0,0 +1,29 @@ +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:9:29 + | +LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} + | ^^^^^^^ + +error: only path types can be used in associated type constraints + --> $DIR/trait-path-types.rs:14:29 + | +LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} + | ^^^^^^^ + +error: only types can be used in associated type constraints + --> $DIR/trait-path-types.rs:19:30 + | +LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} + | ^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-path-types.rs:1:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs new file mode 100644 index 00000000000..02d53d5faee --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs @@ -0,0 +1,17 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +const _: () = { + fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {} + //~^ ERROR: generic associated types in trait paths are currently not implemented +}; + +const _: () = { + fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {} + //~^ ERROR: lifetime in trait object type must be followed by `+` +}; + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr new file mode 100644 index 00000000000..1fba9cebd24 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr @@ -0,0 +1,14 @@ +error: lifetime in trait object type must be followed by `+` + --> $DIR/trait-path-unimplemented.rs:13:31 + | +LL | fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {} + | ^^ + +error: generic associated types in trait paths are currently not implemented + --> $DIR/trait-path-unimplemented.rs:8:30 + | +LL | fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {} + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-20616-2.rs b/src/test/ui/issues/issue-20616-2.rs index 2f2c6903a9f..f108ae5de14 100644 --- a/src/test/ui/issues/issue-20616-2.rs +++ b/src/test/ui/issues/issue-20616-2.rs @@ -9,7 +9,7 @@ type Type_1_<'a, T> = &'a T; //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T` -type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(` +type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,`, `:`, `=`, or `>`, found `(` //type Type_3<T> = Box<T,,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/issues/issue-20616-2.stderr index 50ec7a304c5..01e3d3dd7cc 100644 --- a/src/test/ui/issues/issue-20616-2.stderr +++ b/src/test/ui/issues/issue-20616-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `(` +error: expected one of `,`, `:`, `=`, or `>`, found `(` --> $DIR/issue-20616-2.rs:12:31 | LL | type Type_2 = Type_1_<'static ()>; - | ^ expected one of `,` or `>` + | ^ expected one of `,`, `:`, `=`, or `>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-3.rs b/src/test/ui/issues/issue-20616-3.rs index 9bfd5bf2313..780038c11b8 100644 --- a/src/test/ui/issues/issue-20616-3.rs +++ b/src/test/ui/issues/issue-20616-3.rs @@ -11,7 +11,7 @@ type Type_1_<'a, T> = &'a T; type Type_3<T> = Box<T,,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, const, lifetime, or type, found `,` //type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr index cc4d79484e7..2f8cf8a79ed 100644 --- a/src/test/ui/issues/issue-20616-3.stderr +++ b/src/test/ui/issues/issue-20616-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, const, lifetime, or type, found `,` --> $DIR/issue-20616-3.rs:13:24 | LL | type Type_3<T> = Box<T,,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-4.rs b/src/test/ui/issues/issue-20616-4.rs index e9a34a04667..85aa9c1146d 100644 --- a/src/test/ui/issues/issue-20616-4.rs +++ b/src/test/ui/issues/issue-20616-4.rs @@ -14,7 +14,7 @@ type Type_1_<'a, T> = &'a T; type Type_4<T> = Type_1_<'static,, T>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, const, lifetime, or type, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/ui/issues/issue-20616-4.stderr b/src/test/ui/issues/issue-20616-4.stderr index 254e4d6a34d..3be6c2e78ce 100644 --- a/src/test/ui/issues/issue-20616-4.stderr +++ b/src/test/ui/issues/issue-20616-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, const, lifetime, or type, found `,` --> $DIR/issue-20616-4.rs:16:34 | LL | type Type_4<T> = Type_1_<'static,, T>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-5.rs b/src/test/ui/issues/issue-20616-5.rs index 23862516d2c..c0c6bc6dd97 100644 --- a/src/test/ui/issues/issue-20616-5.rs +++ b/src/test/ui/issues/issue-20616-5.rs @@ -20,7 +20,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_5<'a> = Type_1_<'a, (),,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, const, lifetime, or type, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-5.stderr b/src/test/ui/issues/issue-20616-5.stderr index aee8bf01a43..b90fbf60051 100644 --- a/src/test/ui/issues/issue-20616-5.stderr +++ b/src/test/ui/issues/issue-20616-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, const, lifetime, or type, found `,` --> $DIR/issue-20616-5.rs:22:34 | LL | type Type_5<'a> = Type_1_<'a, (),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-6.rs b/src/test/ui/issues/issue-20616-6.rs index dc327f3f788..73c75bdc45f 100644 --- a/src/test/ui/issues/issue-20616-6.rs +++ b/src/test/ui/issues/issue-20616-6.rs @@ -23,7 +23,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_6 = Type_5_<'a,,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, const, lifetime, or type, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-6.stderr b/src/test/ui/issues/issue-20616-6.stderr index 7192a87bc18..ea1c15ba423 100644 --- a/src/test/ui/issues/issue-20616-6.stderr +++ b/src/test/ui/issues/issue-20616-6.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, const, lifetime, or type, found `,` --> $DIR/issue-20616-6.rs:25:26 | LL | type Type_6 = Type_5_<'a,,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-7.rs b/src/test/ui/issues/issue-20616-7.rs index ffd1620c1d3..8beeebd7a95 100644 --- a/src/test/ui/issues/issue-20616-7.rs +++ b/src/test/ui/issues/issue-20616-7.rs @@ -26,7 +26,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_7 = Box<(),,>; -//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,` +//~^ error: expected one of `>`, const, lifetime, or type, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/ui/issues/issue-20616-7.stderr b/src/test/ui/issues/issue-20616-7.stderr index 123dc1e2b7d..dcd199902fc 100644 --- a/src/test/ui/issues/issue-20616-7.stderr +++ b/src/test/ui/issues/issue-20616-7.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, identifier, lifetime, or type, found `,` +error: expected one of `>`, const, lifetime, or type, found `,` --> $DIR/issue-20616-7.rs:28:22 | LL | type Type_7 = Box<(),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type + | ^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index bf2d091a01e..b45c00f6943 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -1,6 +1,6 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; - //~^ ERROR expected one of `,` or `>`, found `=` + //~^ ERROR only path types can be used in associated type constraints let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index c10a4144305..a9b9bf06d7f 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `=` - --> $DIR/issue-34334.rs:2:29 +error: only path types can be used in associated type constraints + --> $DIR/issue-34334.rs:2:17 | LL | let sr: Vec<(u32, _, _) = vec![]; - | -- ^ expected one of `,` or `>` + | -- ^^^^^^^^^^^ | | | while parsing the type for `sr` diff --git a/src/test/ui/parser/issue-62660.rs b/src/test/ui/parser/issue-62660.rs index 33c8a9fa328..4f866b78976 100644 --- a/src/test/ui/parser/issue-62660.rs +++ b/src/test/ui/parser/issue-62660.rs @@ -5,7 +5,7 @@ struct Foo; impl Foo { pub fn foo(_: i32, self: Box<Self) {} - //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` + //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)` } fn main() {} diff --git a/src/test/ui/parser/issue-62660.stderr b/src/test/ui/parser/issue-62660.stderr index 0844da1bd92..a50ada9056b 100644 --- a/src/test/ui/parser/issue-62660.stderr +++ b/src/test/ui/parser/issue-62660.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` +error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)` --> $DIR/issue-62660.rs:7:38 | LL | pub fn foo(_: i32, self: Box<Self) {} - | ^ expected one of 7 possible tokens + | ^ expected one of 9 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr index 80a450dbd36..e249a93df92 100644 --- a/src/test/ui/parser/issue-63116.stderr +++ b/src/test/ui/parser/issue-63116.stderr @@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;` LL | impl W <s(f;Y(;] | ^ expected one of 7 possible tokens -error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` +error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` --> $DIR/issue-63116.rs:3:15 | LL | impl W <s(f;Y(;] diff --git a/src/test/ui/parser/lifetime-semicolon.rs b/src/test/ui/parser/lifetime-semicolon.rs index 1f147216ea6..7cc14971f63 100644 --- a/src/test/ui/parser/lifetime-semicolon.rs +++ b/src/test/ui/parser/lifetime-semicolon.rs @@ -3,6 +3,6 @@ struct Foo<'a, 'b> { } fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} -//~^ ERROR expected one of `,` or `>`, found `;` +//~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `;` fn main() {} diff --git a/src/test/ui/parser/lifetime-semicolon.stderr b/src/test/ui/parser/lifetime-semicolon.stderr index 4641c286cb8..3b67705aae9 100644 --- a/src/test/ui/parser/lifetime-semicolon.stderr +++ b/src/test/ui/parser/lifetime-semicolon.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `>`, found `;` +error: expected one of `,`, `:`, `=`, or `>`, found `;` --> $DIR/lifetime-semicolon.rs:5:30 | LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} - | ^ expected one of `,` or `>` + | ^ expected one of `,`, `:`, `=`, or `>` error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.rs b/src/test/ui/parser/removed-syntax-closure-lifetime.rs index ceac9408006..e807a179473 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.rs +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.rs @@ -1,2 +1,2 @@ type closure = Box<lt/fn()>; -//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` +//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/` diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr index a100f689fb8..63b6e138ce5 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` +error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/` --> $DIR/removed-syntax-closure-lifetime.rs:1:22 | LL | type closure = Box<lt/fn()>; - | ^ expected one of 7 possible tokens + | ^ expected one of 9 possible tokens error: aborting due to previous error diff --git a/src/test/ui/proc-macro/auxiliary/issue-79242.rs b/src/test/ui/proc-macro/auxiliary/issue-79242.rs new file mode 100644 index 00000000000..e586980f0ad --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-79242.rs @@ -0,0 +1,16 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn dummy(input: TokenStream) -> TokenStream { + // Iterate to force internal conversion of nonterminals + // to `proc_macro` structs + for _ in input {} + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs new file mode 100644 index 00000000000..b68f19c5dd2 --- /dev/null +++ b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs @@ -0,0 +1,34 @@ +// check-pass +// aux-build:issue-79242.rs + +// Regression test for issue #79242 +// Tests that compilation time doesn't blow up for a proc-macro +// invocation with deeply nested nonterminals + +#![allow(unused)] + +extern crate issue_79242; + +macro_rules! declare_nats { + ($prev:ty) => {}; + ($prev:ty, $n:literal$(, $tail:literal)*) => { + + issue_79242::dummy! { + $prev + } + + declare_nats!(Option<$prev>$(, $tail)*); + }; + (0, $($n:literal),+) => { + pub struct N0; + declare_nats!(N0, $($n),+); + }; +} + +declare_nats! { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +} + + +fn main() {} |
