diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index da4d41c9d872f..1c66f8bdf81bd 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -626,9 +626,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyKind::CVarArgs(ref lt) => { visitor.visit_lifetime(lt) } - TyKind::AssocTyExistential(ref bounds) => { - walk_list!(visitor, visit_param_bound, bounds); - } TyKind::Infer | TyKind::Err => {} } } @@ -677,7 +674,14 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { visitor.visit_id(type_binding.hir_id); visitor.visit_ident(type_binding.ident); - visitor.visit_ty(&type_binding.ty); + match type_binding.kind { + TypeBindingKind::Equality { ref ty } => { + visitor.visit_ty(ty); + } + TypeBindingKind::Constraint { ref bounds } => { + walk_list!(visitor, visit_param_bound, bounds); + } + } } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4c96e106d1f1b..1bfff138d8dca 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1377,9 +1377,10 @@ impl<'a> LoweringContext<'a> { -> hir::TypeBinding { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx); - // Convert to a type representing the `T::Item` value. - let ty = match c.kind { - AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx), + let kind = match c.kind { + AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality { + ty: self.lower_ty(ty, itctx) + }, AssocTyConstraintKind::Bound { ref bounds } => { // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { @@ -1422,7 +1423,7 @@ impl<'a> LoweringContext<'a> { if desugar_to_impl_trait { // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by - // constructing the HIR for "impl bounds" and then lowering that. + // constructing the HIR for `impl bounds...` and then lowering that. let impl_trait_node_id = self.sess.next_node_id(); let parent_def_index = self.current_hir_id_owner.last().unwrap().0; @@ -1436,27 +1437,27 @@ impl<'a> LoweringContext<'a> { ); self.with_dyn_type_scope(false, |this| { - this.lower_ty( + let ty = this.lower_ty( &Ty { id: this.sess.next_node_id(), node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), span: DUMMY_SP, }, itctx, - ) + ); + + hir::TypeBindingKind::Equality { + ty + } }) } else { - // Desugar `AssocTy: Bounds` into `AssocTy = ∃ T (T: Bounds)`, where the - // "false existential" later desugars into a trait predicate. - + // Desugar `AssocTy: Bounds` into a type binding where the + // later desugars into a trait predicate. let bounds = self.lower_param_bounds(bounds, itctx); - let id = self.sess.next_node_id(); - P(hir::Ty { - hir_id: self.lower_node_id(id), - node: hir::TyKind::AssocTyExistential(bounds), - span: DUMMY_SP, - }) + hir::TypeBindingKind::Constraint { + bounds + } } } }; @@ -1464,7 +1465,7 @@ impl<'a> LoweringContext<'a> { hir::TypeBinding { hir_id: self.lower_node_id(c.id), ident: c.ident, - ty, + kind, span: c.span, } } @@ -2359,10 +2360,17 @@ impl<'a> LoweringContext<'a> { hir::TypeBinding { hir_id: this.next_id(), ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME), - ty: output - .as_ref() - .map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed())) - .unwrap_or_else(|| P(mk_tup(this, hir::HirVec::new(), span))), + kind: hir::TypeBindingKind::Equality { + ty: output + .as_ref() + .map(|ty| this.lower_ty( + &ty, + ImplTraitContext::disallowed() + )) + .unwrap_or_else(|| + P(mk_tup(this, hir::HirVec::new(), span)) + ), + }, span: output.as_ref().map_or(span, |ty| ty.span), } ], @@ -2666,7 +2674,9 @@ impl<'a> LoweringContext<'a> { args: hir_vec![], bindings: hir_vec![hir::TypeBinding { ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME), - ty: output_ty, + kind: hir::TypeBindingKind::Equality { + ty: output_ty, + }, hir_id: self.next_id(), span, }], diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f884651e8be32..2aaf5ec775d49 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1780,7 +1780,7 @@ pub struct ImplItem { pub span: Span, } -/// Represents different contents within `impl`s. +/// Represents various kinds of content within an `impl`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum ImplItemKind { /// An associated constant of the given type, set to the constant result @@ -1794,16 +1794,51 @@ pub enum ImplItemKind { Existential(GenericBounds), } -// Bind a type to an associated type (`A = Foo`). +/// Bind a type to an associated type (i.e., `A = Foo`). +/// +/// Bindings like `A: Debug` are represented as a special type `A = +/// $::Debug` that is understood by the astconv code. +/// +/// FIXME(alexreg) -- why have a separate type for the binding case, +/// wouldn't it be better to make the `ty` field an enum like: +/// +/// ``` +/// enum TypeBindingKind { +/// Equals(...), +/// Binding(...), +/// } +/// ``` #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct TypeBinding { pub hir_id: HirId, #[stable_hasher(project(name))] pub ident: Ident, - pub ty: P, + pub kind: TypeBindingKind, pub span: Span, } +// Represents the two kinds of type bindings. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum TypeBindingKind { + /// E.g., `Foo`. + Constraint { + bounds: HirVec, + }, + /// E.g., `Foo`. + Equality { + ty: P, + }, +} + +impl TypeBinding { + pub fn ty(&self) -> &Ty { + match self.kind { + TypeBindingKind::Equality { ref ty } => ty, + _ => bug!("expected equality type binding for parenthesized generic args"), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Ty { pub hir_id: HirId, @@ -1898,8 +1933,6 @@ pub enum TyKind { /// Placeholder for C-variadic arguments. We "spoof" the `VaList` created /// from the variadic arguments. This type is only valid up to typeck. CVarArgs(Lifetime), - /// The existential type (i.e., `impl Trait`) that constrains an associated type. - AssocTyExistential(HirVec), } #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] @@ -2236,18 +2269,18 @@ impl StructField { } } -/// Fields and constructor ids of enum variants and structs +/// Fields and constructor IDs of enum variants and structs. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum VariantData { - /// Struct variant. + /// A struct variant. /// - /// e.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. + /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. Struct(HirVec, /* recovered */ bool), - /// Tuple variant. + /// A tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. Tuple(HirVec, HirId), - /// Unit variant. + /// A unit variant. /// /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`. Unit(HirId), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index c8f9e4c7043e0..c8615f0ed1b93 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -409,9 +409,6 @@ impl<'a> State<'a> { hir::TyKind::CVarArgs(_) => { self.s.word("...")?; } - hir::TyKind::AssocTyExistential(ref bounds) => { - self.print_bounds(":", bounds)?; - } } self.end() } @@ -1648,7 +1645,7 @@ impl<'a> State<'a> { self.space_if_not_bol()?; self.word_space("->")?; - self.print_type(&generic_args.bindings[0].ty)?; + self.print_type(generic_args.bindings[0].ty())?; } else { let start = if colons_before_params { "::<" } else { "<" }; let empty = Cell::new(true); @@ -1693,8 +1690,15 @@ impl<'a> State<'a> { start_or_comma(self)?; self.print_ident(binding.ident)?; self.s.space()?; - self.word_space("=")?; - self.print_type(&binding.ty)?; + match generic_args.bindings[0].kind { + hir::TypeBindingKind::Equality { ref ty } => { + self.word_space("=")?; + self.print_type(ty)?; + } + hir::TypeBindingKind::Constraint { ref bounds } => { + self.print_bounds(":", bounds)?; + } + } } if !empty.get() { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2e56ca6f56352..331b74db080bf 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) { let output = match fd.output { hir::DefaultReturn(_) => None, - hir::Return(ref ty) => Some(ty), + hir::Return(ref ty) => Some(&**ty), }; self.visit_fn_like_elision(&fd.inputs, output); } @@ -1884,7 +1884,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if generic_args.parenthesized { let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; - self.visit_fn_like_elision(generic_args.inputs(), Some(&generic_args.bindings[0].ty)); + self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty())); self.is_in_fn_syntax = was_in_fn_syntax; return; } @@ -2020,7 +2020,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx P>) { + fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx hir::Ty>) { debug!("visit_fn_like_elision: enter"); let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); let arg_scope = Scope::Elision { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fe17d902c617c..4a2949fa6b069 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -710,10 +710,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // back separately. let assoc_bindings = generic_args.bindings.iter() .map(|binding| { - let kind = if let hir::TyKind::AssocTyExistential(ref bounds) = binding.ty.node { - ConvertedBindingKind::Constraint(bounds.clone()) - } else { - ConvertedBindingKind::Equality(self.ast_ty_to_ty(&binding.ty)) + let kind = match binding.kind { + hir::TypeBindingKind::Equality { ref ty } => + ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)), + hir::TypeBindingKind::Constraint { ref bounds } => + ConvertedBindingKind::Constraint(bounds.clone()), }; ConvertedBinding { item_name: binding.ident, @@ -2060,10 +2061,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let region = self.ast_region_to_region(<, None); tcx.type_of(va_list_did).subst(tcx, &[region.into()]) } - hir::TyKind::AssocTyExistential(..) => { - // Type is never actually used. - tcx.types.err - } hir::TyKind::Err => { tcx.types.err } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 8e2460a14b87a..60d6c33f81afc 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -626,7 +626,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } => { bindings.push(TypeBinding { name: left_name.clone(), - ty: rhs, + kind: TypeBindingKind::Equality { + ty: rhs, + }, }); } &mut GenericArgs::Parenthesized { .. } => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index af283e6c0bc6f..03d16feb483a9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1979,7 +1979,7 @@ impl FnDecl { match &bounds[0] { GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { let bindings = trait_.bindings().unwrap(); - FunctionRetTy::Return(bindings[0].ty.clone()) + FunctionRetTy::Return(bindings[0].ty().clone()) } _ => panic!("unexpected desugaring of async function"), } @@ -2937,11 +2937,8 @@ impl Clean for hir::Ty { } TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyKind::Infer | TyKind::Err => Infer, - TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node), + TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.node), TyKind::CVarArgs(_) => CVarArgs, - TyKind::AssocTyExistential(ref bounds) => { - ImplTrait(bounds.into_iter().map(|b| b.clean(cx)).collect()) - } } } } @@ -3057,7 +3054,9 @@ impl<'tcx> Clean for Ty<'tcx> { for pb in obj.projection_bounds() { bindings.push(TypeBinding { name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx), - ty: pb.skip_binder().ty.clean(cx) + kind: TypeBindingKind::Equality { + ty: pb.skip_binder().ty.clean(cx) + }, }); } @@ -3113,7 +3112,9 @@ impl<'tcx> Clean for Ty<'tcx> { Some(TypeBinding { name: cx.tcx.associated_item(proj.projection_ty.item_def_id) .ident.name.clean(cx), - ty: proj.ty.clean(cx), + kind: TypeBindingKind::Equality { + ty: proj.ty.clean(cx), + }, }) } else { None @@ -3498,7 +3499,7 @@ pub enum GenericArgs { impl Clean for hir::GenericArgs { fn clean(&self, cx: &DocContext<'_>) -> GenericArgs { if self.parenthesized { - let output = self.bindings[0].ty.clean(cx); + let output = self.bindings[0].ty().clean(cx); GenericArgs::Parenthesized { inputs: self.inputs().clean(cx), output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None } @@ -4346,18 +4347,53 @@ impl Clean for attr::Deprecation { } } -/// An equality constraint on an associated type, e.g., `A = Bar` in `Foo` +/// An type binding on an associated type (e.g., `A = Bar` in `Foo` or +/// `A: Send + Sync` in `Foo`). #[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] pub struct TypeBinding { pub name: String, - pub ty: Type + pub kind: TypeBindingKind, +} + +#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)] +pub enum TypeBindingKind { + Equality { + ty: Type, + }, + Constraint { + bounds: Vec, + }, +} + +impl TypeBinding { + pub fn ty(&self) -> &Type { + match self.kind { + TypeBindingKind::Equality { ref ty } => ty, + _ => panic!("expected equality type binding for parenthesized generic args"), + } + } } impl Clean for hir::TypeBinding { fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { TypeBinding { name: self.ident.name.clean(cx), - ty: self.ty.clean(cx) + kind: self.kind.clean(cx), + } + } +} + +impl Clean for hir::TypeBindingKind { + fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind { + match *self { + hir::TypeBindingKind::Equality { ref ty } => + TypeBindingKind::Equality { + ty: ty.clean(cx), + }, + hir::TypeBindingKind::Constraint { ref bounds } => + TypeBindingKind::Constraint { + bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(), + }, } } } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 8ca570cb443c9..36e6a6003df09 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -91,7 +91,9 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { name: name.clone(), - ty: rhs.clone(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, }); } PP::Parenthesized { ref mut output, .. } => { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 38cde12100056..fa3bc3f5f4f8b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1019,11 +1019,26 @@ impl fmt::Display for clean::ImportSource { impl fmt::Display for clean::TypeBinding { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - write!(f, "{} = {:#}", self.name, self.ty) - } else { - write!(f, "{} = {}", self.name, self.ty) + f.write_str(&self.name)?; + match self.kind { + clean::TypeBindingKind::Equality { ref ty } => { + if f.alternate() { + write!(f, " = {:#}", ty)?; + } else { + write!(f, " = {}", ty)?; + } + } + clean::TypeBindingKind::Constraint { ref bounds } => { + if !bounds.is_empty() { + if f.alternate() { + write!(f, ": {:#}", GenericBounds(bounds))?; + } else { + write!(f, ": {}", GenericBounds(bounds))?; + } + } + } } + Ok(()) } }