From f05d70aee7bdbb3eac1cbc65bb8284e273dc08ab Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 10 Nov 2020 11:34:31 +0100 Subject: [PATCH 1/5] update AST and Parser --- compiler/rustc_ast/src/ast.rs | 13 +- compiler/rustc_ast/src/mut_visit.rs | 5 +- compiler/rustc_ast/src/visit.rs | 3 + .../rustc_ast_passes/src/ast_validation.rs | 27 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 7 + compiler/rustc_parse/src/parser/path.rs | 230 +++++++++++++++--- 6 files changed, 247 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f13d67b9c158..2e91a1059fe0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1095,7 +1095,11 @@ impl Expr { pub fn is_potential_trivial_const_param(&self) -> bool { let this = if let ExprKind::Block(ref block, None) = self.kind { if block.stmts.len() == 1 { - if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self } + if let StmtKind::Expr(ref expr) = block.stmts[0].kind { + expr + } else { + self + } } else { self } @@ -1833,6 +1837,7 @@ impl UintTy { pub struct AssocTyConstraint { pub id: NodeId, pub ident: Ident, + pub gen_args: Vec, pub kind: AssocTyConstraintKind, pub span: Span, } @@ -1938,7 +1943,11 @@ impl TyKind { } pub fn is_unit(&self) -> bool { - if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false } + if let TyKind::Tup(ref tys) = *self { + tys.is_empty() + } else { + false + } } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 517717eebd9d..81ac38811408 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -444,11 +444,14 @@ pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[ } pub fn noop_visit_ty_constraint( - 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); + for arg in gen_args { + vis.visit_generic_arg(arg); + } 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 2ab6667ac3cf..b7826a88dda7 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -490,6 +490,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocTyConstraint, ) { visitor.visit_ident(constraint.ident); + for arg in &constraint.gen_args { + visitor.visit_generic_arg(arg); + } match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { visitor.visit_ty(ty); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6585bcc4259..3275a700502b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1350,6 +1350,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } +fn get_generic_args_from_path_segment(path_segment: &PathSegment) -> Vec { + let mut generic_args: Vec = vec![]; + if let Some(ref args) = path_segment.args { + match &**args { + GenericArgs::AngleBracketed(ref angle_args) => { + for arg in &angle_args.args { + match arg { + AngleBracketedArg::Arg(gen_arg) => match gen_arg { + GenericArg::Lifetime(_) | GenericArg::Type(_) => { + generic_args.push((*gen_arg).clone()) + } + _ => {} + }, + _ => {} + } + } + } + _ => {} + } + } + generic_args +} + /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems /// like it's setting an associated type, provide an appropriate suggestion. fn deny_equality_constraints( @@ -1372,16 +1395,18 @@ fn deny_equality_constraints( if param.ident == *ident { let param = ident; match &full_path.segments[qself.position..] { - [PathSegment { ident, .. }] => { + [path @ PathSegment { ident, .. }] => { // Make a new `Path` from `foo::Bar` to `Foo`. let mut assoc_path = full_path.clone(); // Remove `Bar` from `Foo::Bar`. assoc_path.segments.pop(); let len = assoc_path.segments.len() - 1; + let generic_args = get_generic_args_from_path_segment(&path); // Build ``. let arg = AngleBracketedArg::Constraint(AssocTyConstraint { id: rustc_ast::node_id::DUMMY_NODE_ID, ident: *ident, + gen_args: generic_args, kind: AssocTyConstraintKind::Equality { ty: predicate.rhs_ty.clone(), }, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 9fcba9024433..ddcfce3a721a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -937,6 +937,13 @@ impl<'a> State<'a> { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { self.print_ident(constraint.ident); + if constraint.gen_args.len() > 0 { + self.s.word("<"); + for arg in &constraint.gen_args { + self.print_generic_arg(arg); + } + self.s.word(">"); + } self.s.space(); match &constraint.kind { ast::AssocTyConstraintKind::Equality { ty } => { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 79e737490386..36e62ce0e5ee 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,7 +4,8 @@ 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, + self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, GenericArgs, ParenthesizedArgs, + TyKind, }; use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; use rustc_ast::{Path, PathSegment, QSelf}; @@ -420,7 +421,7 @@ impl<'a> Parser<'a> { 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)?; + let ty = self.parse_assoc_equality_term(Some(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))?; @@ -435,38 +436,92 @@ impl<'a> Parser<'a> { if let AssocTyConstraintKind::Bound { .. } = kind { self.sess.gated_spans.gate(sym::associated_type_bounds, span); } - - let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span }; + let constraint = + AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args: vec![], kind, span }; Ok(Some(AngleBracketedArg::Constraint(constraint))) } else { - Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg)) + let lo = self.token.span; + let arg = self.parse_generic_arg()?; + if self.eat(&token::Eq) { + // Parse the type of the equality constraint even if parsing of the associated type failed + match self.get_assoc_type_with_generic_args(arg, lo) { + Ok((ident, gen_args)) => { + let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; + let kind = AssocTyConstraintKind::Equality { ty }; + let span = lo.to(self.prev_token.span); + let constraint = AssocTyConstraint { + id: ast::DUMMY_NODE_ID, + ident: ident.unwrap(), // parse_assoc_equality_terms return Ok(Some) iff ident is Some + gen_args, + kind, + span, + }; + return Ok(Some(AngleBracketedArg::Constraint(constraint))); + } + Err(err) => { + let _ = self.parse_assoc_equality_term(None, self.prev_token.span); + return Err(err); + } + } + /* + let (ident, gen_args) = self.get_assoc_type_with_generic_args(arg, lo)?; + // Parse the type of the equality constraint even if parsing of the associated type failed + if let Ok(Some(ty)) = self.parse_assoc_equality_term(ident, self.prev_token.span) { + let kind = AssocTyConstraintKind::Equality { ty }; + let span = lo.to(self.prev_token.span); + let constraint = AssocTyConstraint { + id: ast::DUMMY_NODE_ID, + ident: ident.unwrap(), // parse_assoc_equality_terms return Ok(Some) iff ident is Some + gen_args, + kind, + span, + }; + return Ok(Some(AngleBracketedArg::Constraint(constraint))); + */ + } else { + Ok(arg.map(AngleBracketedArg::Arg)) + } } } /// Parse the term to the right of an associated item equality constraint. /// That is, parse `` in `Item = `. /// Right now, this only admits types in ``. - fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P> { + fn parse_assoc_equality_term( + &mut self, + ident: Option, + eq: Span, + ) -> PResult<'a, P> { let arg = self.parse_generic_arg()?; - let span = ident.span.to(self.prev_token.span); - match arg { - Some(GenericArg::Type(ty)) => return Ok(ty), - Some(GenericArg::Const(expr)) => { - self.struct_span_err(span, "cannot constrain an associated constant to a value") + + if let Some(ident) = ident { + let span = ident.span.to(self.prev_token.span); + match arg { + Some(GenericArg::Type(ty)) => return Ok(ty), + Some(GenericArg::Const(expr)) => { + self.struct_span_err( + span, + "cannot constrain an associated constant to a value", + ) .span_label(ident.span, "this associated constant...") .span_label(expr.value.span, "...cannot be constrained to this value") .emit(); - } - Some(GenericArg::Lifetime(lt)) => { - self.struct_span_err(span, "associated lifetimes are not supported") - .span_label(lt.ident.span, "the lifetime is given here") - .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") - .emit(); - } - None => { - let after_eq = eq.shrink_to_hi(); - let before_next = self.token.span.shrink_to_lo(); - self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`") + } + Some(GenericArg::Lifetime(lt)) => { + self.struct_span_err(span, "associated lifetimes are not supported") + .span_label(lt.ident.span, "the lifetime is given here") + .help( + "if you meant to specify a trait object, write `dyn Trait + 'lifetime`", + ) + .emit(); + } + None => { + let after_eq = eq.shrink_to_hi(); + let before_next = self.token.span.shrink_to_lo(); + self.struct_span_err( + after_eq.to(before_next), + "missing type to the right of `=`", + ) .span_suggestion( self.sess.source_map().next_point(eq).to(before_next), "to constrain the associated type, add a type after `=`", @@ -480,9 +535,10 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ) .emit(); + } } } - Ok(self.mk_ty(span, ast::TyKind::Err)) + Ok(self.mk_ty(eq, ast::TyKind::Err)) } /// We do not permit arbitrary expressions as const arguments. They must be one of: @@ -503,35 +559,141 @@ impl<'a> Parser<'a> { /// Parse a generic argument in a path segment. /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. fn parse_generic_arg(&mut self) -> PResult<'a, Option> { - let start = self.token.span; let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. GenericArg::Lifetime(self.expect_lifetime()) } else if self.check_const_arg() { // Parse const argument. - let value = if let token::OpenDelim(token::Brace) = self.token.kind { + let expr = if let token::OpenDelim(token::Brace) = self.token.kind { self.parse_block_expr( None, self.token.span, BlockCheckMode::Default, ast::AttrVec::new(), )? + } else if self.token.is_ident() { + // FIXME(const_generics): to distinguish between idents for types and consts, + // we should introduce a GenericArg::Ident in the AST and distinguish when + // lowering to the HIR. For now, idents for const args are not permitted. + if self.token.is_bool_lit() { + self.parse_literal_maybe_minus()? + } else { + let span = self.token.span; + let msg = "identifiers may currently not be used for const generics"; + self.struct_span_err(span, msg).emit(); + let block = self.mk_block_err(span); + self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new()) + } } else { - self.handle_unambiguous_unbraced_const_arg()? + self.parse_literal_maybe_minus()? }; - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr }) } else if self.check_type() { // Parse type argument. - match self.parse_ty() { - Ok(ty) => GenericArg::Type(ty), - Err(err) => { - // Try to recover from possible `const` arg without braces. - return self.recover_const_arg(start, err).map(Some); - } - } + GenericArg::Type(self.parse_ty()?) } else { return Ok(None); }; Ok(Some(arg)) } + + fn get_assoc_type_with_generic_args( + &self, + gen_arg: Option, + lo: Span, + ) -> PResult<'a, (Option, Vec)> { + if let Some(arg) = gen_arg { + match arg { + GenericArg::Type(t) => match &(*t).kind { + TyKind::Path(_, path) => { + if path.segments.len() == 1 { + let path_seg = &path.segments[0]; + let ident = path_seg.ident; + let gen_args = self.get_generic_args_from_path_segment(&path_seg)?; + debug!("get_assoc_type_with_generic_args gen_args: {:?}", gen_args); + return Ok((Some(ident), gen_args)); + } else { + let mut err = self.struct_span_err( + path.span, + "found a Path with multiple segments, expected a Path with a single segment", + ); + err.span_label(path.span, "expected the name of an associated type"); + err.span_suggestion( + path.span, + "try to use only the last segment:", + format!("{}", path.segments.last().unwrap().ident), + Applicability::MaybeIncorrect, + ); + return Err(err); + } + } + _ => { + let mut err = self.struct_span_err( + lo.to(self.prev_token.span), + "Incorrect type of generic argument, expected a Path with a single path segment", + ); + err.span_label( + self.prev_token.span, + "Expected the name of an associated type", + ); + return Err(err); + } + }, + _ => { + let span = lo.to(self.prev_token.span); + let mut err = self.struct_span_err( + span, + "Incorrect type of generic argument, expected a path with a single segment", + ); + err.span_label(span, "expected the name of an associated type"); + return Err(err); + } + }; + } + // Wrong span here + let err = self.struct_span_err(lo, "unable to parse generic argument"); + Err(err) + } + + fn get_generic_args_from_path_segment( + &self, + path_segment: &PathSegment, + ) -> PResult<'a, Vec> { + debug!("get_generic_args_from_path_segment(path_segment: {:?}", path_segment); + let span = path_segment.ident.span; + let mut generic_args: Vec = vec![]; + if let Some(ref args) = path_segment.args { + match &**args { + GenericArgs::AngleBracketed(ref angle_args) => { + for arg in &angle_args.args { + match arg { + AngleBracketedArg::Arg(gen_arg) => match gen_arg { + GenericArg::Lifetime(_) | GenericArg::Type(_) => { + generic_args.push((*gen_arg).clone()) + } + _ => { + self.struct_span_err( + span, + "generic arguments of associated types must be lifetimes or types", + ) + .emit(); + } + }, + AngleBracketedArg::Constraint(_) => unreachable!(), + } + } + } + GenericArgs::Parenthesized(paren_args) => { + let span = paren_args.span; + self.struct_span_err( + span, + "invalid use of parenthesized generic arguments, expected angle \ + bracketed (`<...>`) generic arguments", + ) + .emit(); + } + } + } + Ok(generic_args) + } } From 6e3ab5d3400ce7f3f9836789535327b0cedef6ad Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 10 Nov 2020 13:18:25 +0100 Subject: [PATCH 2/5] add generic arguments to hir::TypeBinding and update ast lowering --- compiler/rustc_ast_lowering/src/lib.rs | 30 ++++++++++++++++++------- compiler/rustc_ast_lowering/src/path.rs | 5 ++++- compiler/rustc_hir/src/hir.rs | 7 +++++- compiler/rustc_hir/src/intravisit.rs | 2 ++ compiler/rustc_hir_pretty/src/lib.rs | 1 + 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index af2f96d5e625..4d90749613f4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1032,18 +1032,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_assoc_ty_constraint( &mut self, constraint: &AssocTyConstraint, - itctx: ImplTraitContext<'_, 'hir>, + mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); let kind = match constraint.kind { AssocTyConstraintKind::Equality { ref ty } => { - hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } + hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx.reborrow()) } } AssocTyConstraintKind::Bound { ref bounds } => { let mut capturable_lifetimes; // Piggy-back on the `impl Trait` context to figure out the correct behavior. - let (desugar_to_impl_trait, itctx) = match itctx { + let (desugar_to_impl_trait, mut itctx) = match itctx { // We are in the return position: // // fn foo() -> impl Iterator @@ -1052,7 +1052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // fn foo() -> impl Iterator ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx), + | ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx.reborrow()), // We are in the argument position, but within a dyn type: // @@ -1061,7 +1061,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx), + ImplTraitContext::Universal(..) if self.is_in_dyn_type => { + (true, itctx.reborrow()) + } // In `type Foo = dyn Iterator` we desugar to // `type Foo = dyn Iterator` but we have to override the @@ -1087,7 +1089,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so we leave it as is and this gets expanded in astconv to a bound like // `::Item: Debug` where `T` is the type parameter for the // `impl Iterator`. - _ => (false, itctx), + _ => (false, itctx.reborrow()), }; if desugar_to_impl_trait { @@ -1113,7 +1115,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: constraint.span, tokens: None, }, - itctx, + itctx.reborrow(), ); hir::TypeBindingKind::Equality { ty } @@ -1121,16 +1123,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { // Desugar `AssocTy: Bounds` into a type binding where the // later desugars into a trait predicate. - let bounds = self.lower_param_bounds(bounds, itctx); + let bounds = self.lower_param_bounds(bounds, itctx.reborrow()); hir::TypeBindingKind::Constraint { bounds } } } }; + debug!( + "lower_assoc_ty_constraint: generic args of AssocTyConstraint: {:?}", + constraint.gen_args + ); + let args: &'hir mut [GenericArg<'hir>] = self.arena.alloc_from_iter( + constraint.gen_args.iter().map(|arg| self.lower_generic_arg(&arg, itctx.reborrow())), + ); + debug!("lower_assoc_ty_constraint: lowered generic args: {:?}", args); + let bindings: &'hir mut [hir::TypeBinding<'hir>] = arena_vec![self;]; + let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false }); + hir::TypeBinding { hir_id: self.lower_node_id(constraint.id), ident: constraint.ident, + gen_args, kind, span: constraint.span, } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6afed355dc33..8ca919f56629 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -426,6 +426,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::TypeBinding<'hir> { let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME); let kind = hir::TypeBindingKind::Equality { ty }; - hir::TypeBinding { hir_id: self.next_id(), span, ident, kind } + let args = arena_vec![self;]; + let bindings = arena_vec![self;]; + let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false }); + hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3c28b48795f5..ff839c4f7b03 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -497,7 +497,11 @@ pub struct WhereClause<'hir> { impl WhereClause<'_> { pub fn span(&self) -> Option { - if self.predicates.is_empty() { None } else { Some(self.span) } + if self.predicates.is_empty() { + None + } else { + Some(self.span) + } } /// The `WhereClause` under normal circumstances points at either the predicates or the empty @@ -1940,6 +1944,7 @@ pub struct TypeBinding<'hir> { pub hir_id: HirId, #[stable_hasher(project(name))] pub ident: Ident, + pub gen_args: &'hir GenericArgs<'hir>, pub kind: TypeBindingKind<'hir>, pub span: Span, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 35615af0fc7d..f4012ca919d9 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -758,6 +758,8 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>( ) { visitor.visit_id(type_binding.hir_id); visitor.visit_ident(type_binding.ident); + // FIXME: Pass the correct span for the generic arguments here + visitor.visit_generic_args(type_binding.span, type_binding.gen_args); match type_binding.kind { TypeBindingKind::Equality { ref ty } => { visitor.visit_ty(ty); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f7018ae62aa1..dce1d78ff31a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1801,6 +1801,7 @@ impl<'a> State<'a> { for binding in generic_args.bindings.iter() { start_or_comma(self); self.print_ident(binding.ident); + self.print_generic_args(binding.gen_args, false, false); self.s.space(); match generic_args.bindings[0].kind { hir::TypeBindingKind::Equality { ref ty } => { From d279f5e3795e7ba915216cee9e6e9ec0ea6e7bfb Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 10 Nov 2020 14:05:11 +0100 Subject: [PATCH 3/5] include substitutions for generic parameters of associated types in predicates --- .../src/traits/object_safety.rs | 16 +- compiler/rustc_typeck/src/astconv/mod.rs | 170 +++++++++++------- 2 files changed, 117 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 32e0991733bd..5164ed805ee4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -257,13 +257,11 @@ fn predicates_reference_self( } fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) - .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) - .filter_map(|predicate| predicate_references_self(tcx, predicate)) + .filter_map(|pred_span_tuple| predicate_references_self(tcx, *pred_span_tuple)) .collect() } @@ -276,7 +274,11 @@ fn predicate_references_self( match predicate.skip_binders() { ty::PredicateAtom::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. - if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } + if data.trait_ref.substs[1..].iter().any(has_self_ty) { + Some(sp) + } else { + None + } } ty::PredicateAtom::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -528,7 +530,11 @@ fn receiver_for_self_ty<'tcx>( ) -> Ty<'tcx> { debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { - if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } + if param.index == 0 { + self_ty.into() + } else { + tcx.mk_param_from_def(param) + } }); let result = receiver_ty.subst(tcx, substs); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 07e523af3ebf..afe8a9fd2633 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -64,7 +64,7 @@ pub trait AstConv<'tcx> { /// Returns the lifetime to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) - -> Option>; + -> Option>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; @@ -112,12 +112,15 @@ pub enum SizedByDefault { No, } +#[derive(Debug)] struct ConvertedBinding<'a, 'tcx> { item_name: Ident, kind: ConvertedBindingKind<'a, 'tcx>, + gen_args: &'a GenericArgs<'a>, span: Span, } +#[derive(Debug)] enum ConvertedBindingKind<'a, 'tcx> { Equality(Ty<'tcx>), Constraint(&'a [hir::GenericBound<'a>]), @@ -475,7 +478,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ConvertedBindingKind::Constraint(bounds) } }; - ConvertedBinding { item_name: binding.ident, kind, span: binding.span } + ConvertedBinding { + item_name: binding.ident, + kind, + gen_args: binding.gen_args, + span: binding.span, + } }) .collect(); @@ -812,7 +820,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id()); bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } + if !self.is_unsized(ast_bounds, span) { + Some(span) + } else { + None + } } else { None }; @@ -836,60 +848,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { dup_bindings: &mut FxHashMap, path_span: Span, ) -> Result<(), ErrorReported> { - let tcx = self.tcx(); - - if !speculative { - // Given something like `U: SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait: SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B: SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. - - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref. These are not well-formed. - // - // Example: - // - // for<'a> ::Item = &'a str // <-- 'a is bad - // for<'a> >::Output = &'a str // <-- 'a is ok - if let ConvertedBindingKind::Equality(ty) = binding.kind { - let late_bound_in_trait_ref = - tcx.collect_constrained_late_bound_regions(&trait_ref); - let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + // Given something like `U: SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait: SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B: SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1 Fn(&i32, &i32) -> &'a i32>(F); - // ---- ---- ^^^^^^^ - self.validate_late_bound_regions( - late_bound_in_trait_ref, - late_bound_in_ty, - |br_name| { - struct_span_err!( - tcx.sess, - binding.span, - E0582, - "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.item_name, - br_name - ) - }, - ); - } - } + debug!("add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}", + hir_ref_id, trait_ref, binding, bounds); + let tcx = self.tcx(); let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { @@ -948,20 +925,81 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .or_insert(binding.span); } + // Include substitutions for generic parameters of associated types + let candidate_new = candidate.map_bound(|trait_ref| { + let item_segment = hir::PathSegment { + ident: assoc_ty.ident, + hir_id: None, + res: None, + args: Some(binding.gen_args), + infer_args: false, + }; + + let substs_assoc_item = self.create_substs_for_associated_item( + tcx, + path_span, + assoc_ty.def_id, + &item_segment, + trait_ref.substs, + ); + + debug!("substs for assoc_item: {:?}", substs_assoc_item); + ty::TraitRef::new(trait_ref.def_id, substs_assoc_item) + }); + + if !speculative { + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + if let ConvertedBindingKind::Equality(ty) = binding.kind { + let late_bound_in_trait_ref = + tcx.collect_constrained_late_bound_regions(&candidate_new); + let late_bound_in_ty = + tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + self.validate_late_bound_regions( + late_bound_in_trait_ref, + late_bound_in_ty, + |br_name| { + struct_span_err!( + tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + binding.item_name, + br_name + ) + }, + ); + } + } + match binding.kind { ConvertedBindingKind::Equality(ref ty) => { // "Desugar" a constraint like `T: Iterator` this to // the "projection predicate" for: // // `::Item = u32` + bounds.projection_bounds.push(( - candidate.map_bound(|trait_ref| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - binding.item_name, - ), - ty, + candidate_new.map_bound(|trait_ref| { + let projection_ty = + ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, binding.item_name); + debug!( + "projection_ty {:?}, substs: {:?}", + projection_ty, projection_ty.substs + ); + ty::ProjectionPredicate { projection_ty, ty } }), binding.span, )); @@ -1908,7 +1946,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { path_segs.iter().map(|PathSeg(_, index)| index).collect(); self.prohibit_generics(path.segments.iter().enumerate().filter_map( |(index, seg)| { - if !generic_segs.contains(&index) { Some(seg) } else { None } + if !generic_segs.contains(&index) { + Some(seg) + } else { + None + } }, )); From 9e68803036f475b85d638e53e7a2c6e4286b57ba Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 11 Nov 2020 17:33:45 +0100 Subject: [PATCH 4/5] add typeck tests --- .../gat_in_trait_path.rs | 27 +++++++++++++ .../issue-67510-pass.rs | 11 ++++++ .../issue-67510-pass.stderr | 39 +++++++++++++++++++ .../generic-associated-types/issue-67510.rs | 9 +++++ .../issue-67510.stderr | 33 ++++++++++++++++ .../issue-68648-fail-1.rs | 22 +++++++++++ .../issue-68648-fail-1.stderr | 18 +++++++++ .../issue-68648-pass-2.rs | 22 +++++++++++ .../issue-68648-pass.rs | 24 ++++++++++++ .../issue-68649-pass.rs | 22 +++++++++++ .../generic-associated-types/issue-68649.rs | 23 +++++++++++ .../issue-68649.stderr | 21 ++++++++++ .../issue-74684-fail-1.rs | 24 ++++++++++++ .../issue-74684-fail-1.stderr | 18 +++++++++ .../issue-74684-fail-2.rs | 23 +++++++++++ .../issue-74684-fail-2.stderr | 21 ++++++++++ .../issue-74684-pass.rs | 26 +++++++++++++ 17 files changed, 383 insertions(+) create mode 100644 src/test/ui/generic-associated-types/gat_in_trait_path.rs create mode 100644 src/test/ui/generic-associated-types/issue-67510-pass.rs create mode 100644 src/test/ui/generic-associated-types/issue-67510-pass.stderr create mode 100644 src/test/ui/generic-associated-types/issue-67510.rs create mode 100644 src/test/ui/generic-associated-types/issue-67510.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68648-fail-1.rs create mode 100644 src/test/ui/generic-associated-types/issue-68648-fail-1.stderr create mode 100644 src/test/ui/generic-associated-types/issue-68648-pass-2.rs create mode 100644 src/test/ui/generic-associated-types/issue-68648-pass.rs create mode 100644 src/test/ui/generic-associated-types/issue-68649-pass.rs create mode 100644 src/test/ui/generic-associated-types/issue-68649.rs create mode 100644 src/test/ui/generic-associated-types/issue-68649.stderr create mode 100644 src/test/ui/generic-associated-types/issue-74684-fail-1.rs create mode 100644 src/test/ui/generic-associated-types/issue-74684-fail-1.stderr create mode 100644 src/test/ui/generic-associated-types/issue-74684-fail-2.rs create mode 100644 src/test/ui/generic-associated-types/issue-74684-fail-2.stderr create mode 100644 src/test/ui/generic-associated-types/issue-74684-pass.rs diff --git a/src/test/ui/generic-associated-types/gat_in_trait_path.rs b/src/test/ui/generic-associated-types/gat_in_trait_path.rs new file mode 100644 index 000000000000..c47c1e2eab0a --- /dev/null +++ b/src/test/ui/generic-associated-types/gat_in_trait_path.rs @@ -0,0 +1,27 @@ +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +trait Foo { + type A<'a> where Self: 'a; +} + +struct Fooy; + +impl Foo for Fooy { + type A<'a> = (&'a ()); +} + +#[derive(Clone)] +struct Fooer(T); + +impl Foo for Fooer { + type A<'x> where T: 'x = (&'x ()); +} + +fn f(arg : Box Foo = &'a ()>>) {} + + +fn main() { + let foo = Fooer(5); + f(Box::new(foo)); +} diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs new file mode 100644 index 000000000000..d89298753ace --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs @@ -0,0 +1,11 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn func1<'a>(x: Box=&'a ()>>) {} + +fn func2(x: Box X=&'a ()>>) {} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr new file mode 100644 index 000000000000..4ea12356432c --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -0,0 +1,39 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + + +warning: unused variable: `x` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:7:14 + | +7 | fn func1<'a>(x: Box=&'a ()>>) {} + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: `#[warn(unused_variables)]` on by default + +warning: unused variable: `x` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:9:10 + | +9 | fn func2(x: Box X=&'a ()>>) {} + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +warning: function is never used: `func1` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:7:4 + | +7 | fn func1<'a>(x: Box=&'a ()>>) {} + | ^^^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: function is never used: `func2` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510-pass.rs:9:4 + | +9 | fn func2(x: Box X=&'a ()>>) {} + | ^^^^^ + +warning: 5 warnings emitted diff --git a/src/test/ui/generic-associated-types/issue-67510.rs b/src/test/ui/generic-associated-types/issue-67510.rs new file mode 100644 index 000000000000..834913f9ec6a --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67510.rs @@ -0,0 +1,9 @@ +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f(x: Box=&'a ()>>) {} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr new file mode 100644 index 000000000000..b518295476fa --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-67510.stderr @@ -0,0 +1,33 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + + +error[E0261]: use of undeclared lifetime name `'a` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:7:21 + | +7 | fn f(x: Box=&'a ()>>) {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error[E0261]: use of undeclared lifetime name `'a` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-67510.rs:7:26 + | +7 | fn f(x: Box=&'a ()>>) {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + | + = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/generic-associated-types/issue-68648-fail-1.rs b/src/test/ui/generic-associated-types/issue-68648-fail-1.rs new file mode 100644 index 000000000000..7a56f8c69cc6 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68648-fail-1.rs @@ -0,0 +1,22 @@ +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>; + + fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun>(t: T) -> T::F<'a> { + T::identity(t) +} + + +fn main() { + let x = 10; + + bug(x); +} diff --git a/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr b/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr new file mode 100644 index 000000000000..6cb6798ed004 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr @@ -0,0 +1,18 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68648-fail-1.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0107]: wrong number of lifetime arguments: expected 1, found 0 + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68648-fail-1.rs:13:19 + | +13 | fn bug<'a, T: Fun>(t: T) -> T::F<'a> { + | ^^^^^ expected 1 lifetime argument + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/issue-68648-pass-2.rs b/src/test/ui/generic-associated-types/issue-68648-pass-2.rs new file mode 100644 index 000000000000..9460e08a4229 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68648-pass-2.rs @@ -0,0 +1,22 @@ +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>; + + fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: for<'b> Fun = T>>(t: T) -> T::F<'a> { + T::identity(t) +} + + +fn main() { + let x = 10; + + bug(x); +} diff --git a/src/test/ui/generic-associated-types/issue-68648-pass.rs b/src/test/ui/generic-associated-types/issue-68648-pass.rs new file mode 100644 index 000000000000..2a1c98c3040b --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68648-pass.rs @@ -0,0 +1,24 @@ +// build-pass + +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>; + + fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun = T>>(t: T) -> T::F<'a> { + T::identity(t) +} + + +fn main() { + let x = 10; + + bug(x); +} diff --git a/src/test/ui/generic-associated-types/issue-68649-pass.rs b/src/test/ui/generic-associated-types/issue-68649-pass.rs new file mode 100644 index 000000000000..295f99938965 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68649-pass.rs @@ -0,0 +1,22 @@ +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>; + + fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun>(t: T) -> T::F<'a> { + T::identity(()) +} + + +fn main() { + let x = 10; + + bug(x); +} diff --git a/src/test/ui/generic-associated-types/issue-68649.rs b/src/test/ui/generic-associated-types/issue-68649.rs new file mode 100644 index 000000000000..20e18cf05299 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68649.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>; + + fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: for<'b> Fun = ()>>(t: T) -> T::F<'a> { + T::identity(()) + //~^ ERROR: type mismatch resolving `for<'b> <{integer} as Fun>::F<'b> == ()` +} + + +fn main() { + let x = 10; + + bug(x); +} diff --git a/src/test/ui/generic-associated-types/issue-68649.stderr b/src/test/ui/generic-associated-types/issue-68649.stderr new file mode 100644 index 000000000000..c52fe8900e0c --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68649.stderr @@ -0,0 +1,21 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68649.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0271]: type mismatch resolving `for<'b> <{integer} as Fun>::F<'b> == ()` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-68649.rs:22:5 + | +13 | fn bug<'a, T: for<'b> Fun = ()>>(t: T) -> T::F<'a> { + | ---------- required by this bound in `bug` +... +22 | bug(x); + | ^^^ expected `()`, found integer + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-1.rs b/src/test/ui/generic-associated-types/issue-74684-fail-1.rs new file mode 100644 index 000000000000..f1fbb9ba0b11 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74684-fail-1.rs @@ -0,0 +1,24 @@ +#![feature(generic_associated_types)] +trait Fun { + type F<'a>: ?Sized; + + fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = i32; +} + +fn bug<'a, T: ?Sized + Fun>(t: Box) -> &'static T::F<'a> { + //~^ ERROR: wrong number of lifetime arguments: expected 1, found 0 + let a = [0; 1]; + let x = T::identity(&a); + todo!() +} + + +fn main() { + let x = 10; + + bug(Box::new(x)); +} diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr b/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr new file mode 100644 index 000000000000..f4d202e65c70 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74684-fail-1.stderr @@ -0,0 +1,18 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-1.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0107]: wrong number of lifetime arguments: expected 1, found 0 + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-1.rs:12:28 + | +12 | fn bug<'a, T: ?Sized + Fun>(t: Box) -> &'static T::F<'a> { + | ^^^^^^^^ expected 1 lifetime argument + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-2.rs b/src/test/ui/generic-associated-types/issue-74684-fail-2.rs new file mode 100644 index 000000000000..0d1c078df009 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74684-fail-2.rs @@ -0,0 +1,23 @@ +#![feature(generic_associated_types)] +trait Fun { + type F<'a>: ?Sized; + + fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = i32; +} + +fn bug<'a, T: ?Sized + Fun = [u8]>>(t: Box) -> &'static T::F<'a> { + let a = [0; 1]; + let x = T::identity(&a); + todo!() +} + + +fn main() { + let x = 10; + + bug(Box::new(x)); +} diff --git a/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr b/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr new file mode 100644 index 000000000000..3fa3119694c3 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74684-fail-2.stderr @@ -0,0 +1,21 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-2.rs:1:12 + | +1 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0271]: type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/issue-74684-fail-2.rs:22:5 + | +12 | fn bug<'a, T: ?Sized + Fun = [u8]>>(t: Box) -> &'static T::F<'a> { + | ------------ required by this bound in `bug` +... +22 | bug(Box::new(x)); + | ^^^ expected slice `[u8]`, found `i32` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/issue-74684-pass.rs b/src/test/ui/generic-associated-types/issue-74684-pass.rs new file mode 100644 index 000000000000..7d27954e0fbe --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74684-pass.rs @@ -0,0 +1,26 @@ +// build-pass + +#![feature(generic_associated_types)] + +trait Fun { + type F<'a>: ?Sized; + + fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t } +} + +impl Fun for T { + type F<'a> = [u8]; +} + +fn bug<'a, T: ?Sized + Fun = [u8]>>(t: Box) -> &'static T::F<'a> { + let a = [0; 1]; + let x = T::identity(&a); + todo!() +} + + +fn main() { + let x = 10; + + bug(Box::new(x)); +} From 98e53ac25137f88010b0195257da49d55c75d341 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 11 Nov 2020 18:58:28 +0100 Subject: [PATCH 5/5] add tests for parser --- .../parse/issue-67510-1.rs | 16 ++++++++++ .../parse/issue-67510-1.stderr | 10 +++++++ .../parse/issue-67510-2.rs | 12 ++++++++ .../parse/issue-67510-2.stderr | 18 +++++++++++ .../parse/issue-67510-3.rs | 12 ++++++++ .../parse/issue-67510-3.stderr | 16 ++++++++++ .../parse/issue-67510-4.rs | 14 +++++++++ .../parse/issue-67510-4.stderr | 24 +++++++++++++++ .../parse/issue-67510-5.rs | 12 ++++++++ .../parse/issue-67510-5.stderr | 16 ++++++++++ .../parse/issue-67510-6.rs | 16 ++++++++++ .../parse/issue-67510-6.stderr | 30 +++++++++++++++++++ 12 files changed, 196 insertions(+) create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-1.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-1.stderr create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-2.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-2.stderr create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-3.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-3.stderr create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-4.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-4.stderr create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-5.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-5.stderr create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-6.rs create mode 100644 src/test/ui/generic-associated-types/parse/issue-67510-6.stderr diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-1.rs b/src/test/ui/generic-associated-types/parse/issue-67510-1.rs new file mode 100644 index 000000000000..5be5013283ec --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-1.rs @@ -0,0 +1,16 @@ +// Several parsing errors for associated type constraints that are supposed +// to trigger all errors in ´get_assoc_type_with_generics´ and +// ´get_generic_args_from_path_segment´ + +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +trait Z {} + +impl = &'a u32>> Z for T {} + //~^ ERROR: associated types cannot contain multiple path segments + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr new file mode 100644 index 000000000000..256c926919d2 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-1.stderr @@ -0,0 +1,10 @@ +error: found a Path with multiple segments, expected a Path with a single segment + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-1.rs:13:12 + | +13 | impl = &'a u32>> Z for T {} + | ^^^^^^^^ + | | + | expected the name of an associated type + | help: try to use only the last segment:: `Y` + +error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-2.rs b/src/test/ui/generic-associated-types/parse/issue-67510-2.rs new file mode 100644 index 000000000000..4f946d50d9ce --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-2.rs @@ -0,0 +1,12 @@ +// Only accept generic arguments of typeTyKind::Path as associated types in +// trait paths +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box) = &'a ()>>) {} + //~^ ERROR: Expected the name of an associated type + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr new file mode 100644 index 000000000000..40816c27fa17 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-2.stderr @@ -0,0 +1,18 @@ +error: Incorrect type of generic argument, expected a Path with a single path segment + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-2.rs:9:27 + | +9 | fn f1<'a>(arg : Box) = &'a ()>>) {} + | ^^^^^^^^- + | | + | Expected the name of an associated type + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-2.rs:3:12 + | +3 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-3.rs b/src/test/ui/generic-associated-types/parse/issue-67510-3.rs new file mode 100644 index 000000000000..6cdf4fdb7caf --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-3.rs @@ -0,0 +1,12 @@ +// Test to ensure that only GenericArg::Type is accepted in associated type +// constraints +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box>) {} + //~^ ERROR: Expected the name of an associated type + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr new file mode 100644 index 000000000000..faa8a18f000b --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-3.stderr @@ -0,0 +1,16 @@ +error: Incorrect type of generic argument, expected a path with a single segment + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-3.rs:9:27 + | +9 | fn f1<'a>(arg : Box>) {} + | ^^^^ expected the name of an associated type + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-3.rs:3:12 + | +3 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-4.rs b/src/test/ui/generic-associated-types/parse/issue-67510-4.rs new file mode 100644 index 000000000000..fef5b286b833 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-4.rs @@ -0,0 +1,14 @@ +// Only accept lifetimes or types as generic arguments for associated types +// in trait paths + +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box = &'a ()>>) {} + //~^ ERROR: generic arguments of associated types must be lifetimes or types + //~^^ ERROR: wrong number of lifetime arguments: expected 1, found 0 + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr new file mode 100644 index 000000000000..780a44a45505 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-4.stderr @@ -0,0 +1,24 @@ +error: generic arguments of associated types must be lifetimes or types + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:10:27 + | +10 | fn f1<'a>(arg : Box = &'a ()>>) {} + | ^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:4:12 + | +4 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0107]: wrong number of lifetime arguments: expected 1, found 0 + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-4.rs:10:27 + | +10 | fn f1<'a>(arg : Box = &'a ()>>) {} + | ^^^^^^^^^^^^^ expected 1 lifetime argument + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-5.rs b/src/test/ui/generic-associated-types/parse/issue-67510-5.rs new file mode 100644 index 000000000000..778b68467cad --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-5.rs @@ -0,0 +1,12 @@ +// Test to ensure that the Constraint branch of the pattern match on AngleBracketedArg +// in `get_assoc_type_with_generic_args` is unreachable +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box>) {} + //~^ ERROR: Expected the name of an associated type + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr new file mode 100644 index 000000000000..e3ce57ee662c --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-5.stderr @@ -0,0 +1,16 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-5.rs:9:33 + | +9 | fn f1<'a>(arg : Box>) {} + | ^ 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 + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-5.rs:3:12 + | +3 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-6.rs b/src/test/ui/generic-associated-types/parse/issue-67510-6.rs new file mode 100644 index 000000000000..8b9ce62da152 --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-6.rs @@ -0,0 +1,16 @@ +// Parser shouldn't accept parenthesized generic arguments for associated types in +// trait paths +#![feature(generic_associated_types)] + +trait X { + type Y<'a>; +} + +fn f1<'a>(arg : Box>) {} + //~^ ERROR: lifetime in trait object type must be followed by `+` + //~^^ ERROR: invalid use of parenthesized generic arguments, expected angle + // bracketed (`<...>`) generic arguments + //~^^^^ ERROR: wrong number of lifetime arguments: expected 1, found 0 + + +fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr b/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr new file mode 100644 index 000000000000..d24a1b2acc9f --- /dev/null +++ b/src/test/ui/generic-associated-types/parse/issue-67510-6.stderr @@ -0,0 +1,30 @@ +error: lifetime in trait object type must be followed by `+` + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:29 + | +9 | fn f1<'a>(arg : Box>) {} + | ^^ + +error: invalid use of parenthesized generic arguments, expected angle bracketed (`<...>`) generic arguments + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:27 + | +9 | fn f1<'a>(arg : Box>) {} + | ^^^^^ + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:3:12 + | +3 | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0107]: wrong number of lifetime arguments: expected 1, found 0 + --> /Users/bn/Documents/rust_fork/rust/src/test/ui/generic-associated-types/parse/issue-67510-6.rs:9:27 + | +9 | fn f1<'a>(arg : Box>) {} + | ^^^^^^^^^^^^^^ expected 1 lifetime argument + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`.