diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f13d67b9c1584..2e91a1059fe0c 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<GenericArg>, 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 517717eebd9d0..81ac388114083 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<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); + 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 2ab6667ac3cf1..b7826a88dda7f 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_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index af2f96d5e6253..4d90749613f40 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<Item: Debug> @@ -1052,7 +1052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // fn foo() -> impl Iterator<Item = impl Debug> 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<Item = impl Debug>) - 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<Item: Debug>` we desugar to // `type Foo = dyn Iterator<Item = impl Debug>` 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 // `<T as Iterator>::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 6afed355dc338..8ca919f56629f 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_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6585bcc4259b..3275a700502b4 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<GenericArg> { + let mut generic_args: Vec<GenericArg> = 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<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 generic_args = get_generic_args_from_path_segment(&path); // Build `<Bar = RhsTy>`. 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 9fcba90244330..ddcfce3a721ad 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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3c28b48795f56..ff839c4f7b039 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<Span> { - 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 35615af0fc7df..f4012ca919d9b 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 f7018ae62aa19..dce1d78ff31a9 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 } => { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 79e737490386c..36e62ce0e5eeb 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 `<term>` in `Item = <term>`. /// Right now, this only admits types in `<term>`. - fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> { + fn parse_assoc_equality_term( + &mut self, + ident: Option<Ident>, + eq: Span, + ) -> PResult<'a, P<ast::Ty>> { 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<GenericArg>> { - 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<GenericArg>, + lo: Span, + ) -> PResult<'a, (Option<Ident>, Vec<GenericArg>)> { + 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<GenericArg>> { + debug!("get_generic_args_from_path_segment(path_segment: {:?}", path_segment); + let span = path_segment.ident.span; + let mut generic_args: Vec<GenericArg> = 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) + } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 32e0991733bd9..5164ed805ee42 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 07e523af3ebf5..afe8a9fd26337 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<ty::Region<'tcx>>; + -> Option<ty::Region<'tcx>>; /// 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<DefId, Span>, path_span: Span, ) -> Result<(), ErrorReported> { - let tcx = self.tcx(); - - if !speculative { - // Given something like `U: SomeTrait<T = X>`, we want to produce a - // predicate like `<U as SomeTrait>::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<i32> { } - // trait SuperTrait<A> { type T; } - // - // ... B: SubTrait<T = foo> ... - // ``` - // - // We want to produce `<B as SuperTrait<i32>>::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> <T as Iterator>::Item = &'a str // <-- 'a is bad - // for<'a> <T as FnMut<(&'a u32,)>>::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<T = X>`, we want to produce a + // predicate like `<U as SomeTrait>::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<i32> { } + // trait SuperTrait<A> { type T; } + // + // ... B: SubTrait<T = foo> ... + // ``` + // + // We want to produce `<B as SuperTrait<i32>>::T == foo`. - // FIXME: point at the type params that don't have appropriate lifetimes: - // struct S1<F: for<'a> 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> <T as Iterator>::Item = &'a str // <-- 'a is bad + // for<'a> <T as FnMut<(&'a u32,)>>::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<F: for<'a> 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<Item = u32>` this to // the "projection predicate" for: // // `<T as Iterator>::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 + } }, )); 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 0000000000000..c47c1e2eab0a4 --- /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>(T); + +impl<T> Foo for Fooer<T> { + type A<'x> where T: 'x = (&'x ()); +} + +fn f(arg : Box<dyn for<'a> Foo<A<'a> = &'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 0000000000000..d89298753ace3 --- /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<dyn X<Y<'a>=&'a ()>>) {} + +fn func2(x: Box<dyn for<'a> X<Y<'a>=&'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 0000000000000..4ea12356432c7 --- /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 <https://github.com/rust-lang/rust/issues/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<dyn X<Y<'a>=&'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<dyn for<'a> X<Y<'a>=&'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<dyn X<Y<'a>=&'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<dyn for<'a> X<Y<'a>=&'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 0000000000000..834913f9ec6a3 --- /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<dyn X<Y<'a>=&'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 0000000000000..b518295476fa0 --- /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 <https://github.com/rust-lang/rust/issues/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<dyn X<Y<'a>=&'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<dyn X<Y<'a>=&'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 0000000000000..7a56f8c69cc64 --- /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 <T> Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun<F = 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-fail-1.stderr b/src/test/ui/generic-associated-types/issue-68648-fail-1.stderr new file mode 100644 index 0000000000000..6cb6798ed004d --- /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 <https://github.com/rust-lang/rust/issues/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<F = T>>(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 0000000000000..9460e08a4229a --- /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 <T> Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: for<'b> Fun<F<'b> = 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 0000000000000..2a1c98c3040b1 --- /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 <T> Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun<F<'a> = 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 0000000000000..295f999389655 --- /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 <T> Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: Fun<F = ()>>(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 0000000000000..20e18cf052993 --- /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 <T> Fun for T { + type F<'a> = Self; +} + +fn bug<'a, T: for<'b> Fun<F<'b> = ()>>(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 0000000000000..c52fe8900e0c3 --- /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 <https://github.com/rust-lang/rust/issues/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<F<'b> = ()>>(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 0000000000000..f1fbb9ba0b113 --- /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 <T> Fun for T { + type F<'a> = i32; +} + +fn bug<'a, T: ?Sized + Fun<F = [u8]>>(t: Box<T>) -> &'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 0000000000000..f4d202e65c70d --- /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 <https://github.com/rust-lang/rust/issues/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<F = [u8]>>(t: Box<T>) -> &'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 0000000000000..0d1c078df009b --- /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 <T> Fun for T { + type F<'a> = i32; +} + +fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(t: Box<T>) -> &'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 0000000000000..3fa3119694c32 --- /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 <https://github.com/rust-lang/rust/issues/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<F<'a> = [u8]>>(t: Box<T>) -> &'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 0000000000000..7d27954e0fbe4 --- /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 <T> Fun for T { + type F<'a> = [u8]; +} + +fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(t: Box<T>) -> &'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/parse/issue-67510-1.rs b/src/test/ui/generic-associated-types/parse/issue-67510-1.rs new file mode 100644 index 0000000000000..5be5013283ec0 --- /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<T : X<X::Y<'a> = &'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 0000000000000..256c926919d25 --- /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<T : X<X::Y<'a> = &'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 0000000000000..4f946d50d9cef --- /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<dyn X<(Y<'a>) = &'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 0000000000000..40816c27fa17f --- /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<dyn X<(Y<'a>) = &'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 <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/issue-67510-3.rs b/src/test/ui/generic-associated-types/parse/issue-67510-3.rs new file mode 100644 index 0000000000000..6cdf4fdb7cafd --- /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<dyn X<'a = &'a ()>>) {} + //~^ 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 0000000000000..faa8a18f000b3 --- /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<dyn X<'a = &'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-3.rs:3:12 + | +3 | #![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/issue-67510-4.rs b/src/test/ui/generic-associated-types/parse/issue-67510-4.rs new file mode 100644 index 0000000000000..fef5b286b8333 --- /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<dyn X<Y<1> = &'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 0000000000000..780a44a455059 --- /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<dyn X<Y<1> = &'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 <https://github.com/rust-lang/rust/issues/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<dyn X<Y<1> = &'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 0000000000000..778b68467cad7 --- /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<dyn X<Y = B = &'a ()>>) {} + //~^ 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 0000000000000..e3ce57ee662c0 --- /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<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 + --> /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 <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/issue-67510-6.rs b/src/test/ui/generic-associated-types/parse/issue-67510-6.rs new file mode 100644 index 0000000000000..8b9ce62da1528 --- /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<dyn X<Y('a) = &'a ()>>) {} + //~^ 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 0000000000000..d24a1b2acc9f8 --- /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<dyn X<Y('a) = &'a ()>>) {} + | ^^ + +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<dyn X<Y('a) = &'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-6.rs:3:12 + | +3 | #![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[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<dyn X<Y('a) = &'a ()>>) {} + | ^^^^^^^^^^^^^^ expected 1 lifetime argument + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0107`.