diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb..f0c1d017326 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -387,23 +387,23 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.print_string(sym.as_str(), style); } - fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } - fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false) } - fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) { + fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) } - fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true) } - fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) { + fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true) } @@ -413,20 +413,21 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere kind: ast::AttrStyle, is_inline: bool, trailing_hardbreak: bool, - ) { - let mut count = 0; + ) -> bool { + let mut printed = false; for attr in attrs { if attr.style == kind { self.print_attribute_inline(attr, is_inline); if is_inline { self.nbsp(); } - count += 1; + printed = true; } } - if count > 0 && trailing_hardbreak && !is_inline { + if printed && trailing_hardbreak && !is_inline { self.hardbreak_if_not_bol(); } + printed } fn print_attribute(&mut self, attr: &ast::Attribute) { @@ -1646,7 +1647,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Block(blk)); self.bopen(); - self.print_inner_attributes(attrs); + let has_attrs = self.print_inner_attributes(attrs); for (i, st) in blk.stmts.iter().enumerate() { match st.kind { @@ -1660,7 +1661,7 @@ impl<'a> State<'a> { } } - let empty = attrs.is_empty() && blk.stmts.is_empty(); + let empty = !has_attrs && blk.stmts.is_empty(); self.bclose_maybe_open(blk.span, empty, close_box); self.ann.post(self, AnnNode::Block(blk)) } @@ -2780,34 +2781,34 @@ impl<'a> State<'a> { self.word_space(","); } - match *predicate { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - ref bound_generic_params, - ref bounded_ty, - ref bounds, - .. - }) => { - self.print_formal_generic_params(bound_generic_params); - self.print_type(bounded_ty); - self.print_type_bounds(":", bounds); - } - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - ref lifetime, - ref bounds, - .. - }) => { - self.print_lifetime_bounds(*lifetime, bounds); - } - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - ref lhs_ty, - ref rhs_ty, - .. - }) => { - self.print_type(lhs_ty); - self.space(); - self.word_space("="); - self.print_type(rhs_ty); - } + self.print_where_predicate(predicate); + } + } + + pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { + match predicate { + ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + bound_generic_params, + bounded_ty, + bounds, + .. + }) => { + self.print_formal_generic_params(bound_generic_params); + self.print_type(bounded_ty); + self.print_type_bounds(":", bounds); + } + ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { + lifetime, + bounds, + .. + }) => { + self.print_lifetime_bounds(*lifetime, bounds); + } + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + self.print_type(lhs_ty); + self.space(); + self.word_space("="); + self.print_type(rhs_ty); } } } @@ -2908,10 +2909,7 @@ impl<'a> State<'a> { generic_params: &[ast::GenericParam], ) { self.ibox(INDENT_UNIT); - if !generic_params.is_empty() { - self.word("for"); - self.print_generic_params(generic_params); - } + self.print_formal_generic_params(generic_params); let generics = ast::Generics { params: Vec::new(), where_clause: ast::WhereClause { diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index ce26ff62235..79d9c55b547 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"), E0224: include_str!("./error_codes/E0224.md"), E0225: include_str!("./error_codes/E0225.md"), E0226: include_str!("./error_codes/E0226.md"), +E0227: include_str!("./error_codes/E0227.md"), E0228: include_str!("./error_codes/E0228.md"), E0229: include_str!("./error_codes/E0229.md"), E0230: include_str!("./error_codes/E0230.md"), @@ -530,7 +531,6 @@ E0786: include_str!("./error_codes/E0786.md"), // E0217, // ambiguous associated type, defined in multiple supertraits // E0218, // no associated type defined // E0219, // associated type defined in higher-ranked supertrait - E0227, // ambiguous lifetime bound, explicit lifetime bound required // E0233, // E0234, // E0235, // structure constructor specifies a structure of type but diff --git a/compiler/rustc_error_codes/src/error_codes/E0227.md b/compiler/rustc_error_codes/src/error_codes/E0227.md new file mode 100644 index 00000000000..f68614723d4 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0227.md @@ -0,0 +1,33 @@ +This error indicates that the compiler is unable to determine whether there is +exactly one unique region in the set of derived region bounds. + +Example of erroneous code: + +```compile_fail,E0227 +trait Foo<'foo>: 'foo {} +trait Bar<'bar>: 'bar {} + +trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} + +struct Baz<'foo, 'bar> { + baz: dyn FooBar<'foo, 'bar>, +} +``` + +Here, `baz` can have either `'foo` or `'bar` lifetimes. + +To resolve this error, provide an explicit lifetime: + +```rust +trait Foo<'foo>: 'foo {} +trait Bar<'bar>: 'bar {} + +trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} + +struct Baz<'foo, 'bar, 'baz> +where + 'baz: 'foo + 'bar, +{ + obj: dyn FooBar<'foo, 'bar> + 'baz, +} +``` diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2f5f158856f..334fa6f4e5c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2327,10 +2327,7 @@ impl<'a> State<'a> { arg_names: &[Ident], ) { self.ibox(INDENT_UNIT); - if !generic_params.is_empty() { - self.word("for"); - self.print_generic_params(generic_params); - } + self.print_formal_generic_params(generic_params); let generics = hir::Generics { params: &[], where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP }, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 618aa3fd002..d335ef8788b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -794,6 +794,44 @@ impl<'a> Parser<'a> { )) } + /// Emits an error that the where clause at the end of a type alias is not + /// allowed and suggests moving it. + fn error_ty_alias_where( + &self, + before_where_clause_present: bool, + before_where_clause_span: Span, + after_predicates: &[WherePredicate], + after_where_clause_span: Span, + ) { + let mut err = + self.struct_span_err(after_where_clause_span, "where clause not allowed here"); + if !after_predicates.is_empty() { + let mut state = crate::pprust::State::new(); + if !before_where_clause_present { + state.space(); + state.word_space("where"); + } else { + state.word_space(","); + } + let mut first = true; + for p in after_predicates.iter() { + if !first { + state.word_space(","); + } + first = false; + state.print_where_predicate(p); + } + let suggestion = state.s.eof(); + err.span_suggestion( + before_where_clause_span.shrink_to_hi(), + "move it here", + suggestion, + Applicability::MachineApplicable, + ); + } + err.emit() + } + /// Parses a `type` alias with the following grammar: /// ``` /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; @@ -806,9 +844,24 @@ impl<'a> Parser<'a> { // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() }; + generics.where_clause = self.parse_where_clause()?; let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; + + if self.token.is_keyword(kw::Where) { + let after_where_clause = self.parse_where_clause()?; + + self.error_ty_alias_where( + generics.where_clause.has_where_token, + generics.where_clause.span, + &after_where_clause.predicates, + after_where_clause.span, + ); + + generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter()); + } + self.expect_semi()?; Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty })))) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 12123c946cc..5098cef11e8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1603,10 +1603,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { pat_src: PatternSource, bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet); 1]>, ) { + // We walk the pattern before declaring the pattern's inner bindings, + // so that we avoid resolving a literal expression to a binding defined + // by the pattern. + visit::walk_pat(self, pat); self.resolve_pattern_inner(pat, pat_src, bindings); // This has to happen *after* we determine which pat_idents are variants: self.check_consistent_bindings_top(pat); - visit::walk_pat(self, pat); } /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d928b41cad4..2b1a1d4a600 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -39,7 +39,6 @@ use crate::clean::Clean; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::cache::ExternalLocation; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; @@ -339,6 +338,16 @@ impl ExternalCrate { } } +/// Indicates where an external crate can be found. +crate enum ExternalLocation { + /// Remote URL root of the external crate + Remote(String), + /// This external crate can be found in the local doc/ folder + Local, + /// The external crate could not be found. + Unknown, +} + /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5813062ceab..6b9ccd37cfb 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -6,13 +6,13 @@ use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; -use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::markdown::short_markdown_summary; -use crate::html::render::cache::{get_index_search_type, ExternalLocation}; +use crate::html::render::search_index::get_function_type_for_search; use crate::html::render::IndexItem; /// This cache is used to store information about the [`clean::Crate`] being @@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { desc, parent, parent_idx: None, - search_type: get_index_search_type(&item, self.tcx, self.cache), + search_type: get_function_type_for_search(&item, self.tcx), aliases: item.attrs.get_doc_aliases(), }); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e4c612aaab9..3a7c7186877 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -21,10 +21,12 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; -use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType}; +use crate::clean::{ + self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId, + PrimitiveType, +}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; -use crate::html::render::cache::ExternalLocation; use crate::html::render::Context; use super::url_parts_builder::UrlPartsBuilder; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 45a436c4487..534a542d58e 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -13,8 +13,8 @@ use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use rustc_span::symbol::sym; -use super::cache::{build_index, ExternalLocation}; use super::print_item::{full_path, item_path, print_item}; +use super::search_index::build_index; use super::templates; use super::write_shared::write_shared; use super::{ @@ -22,7 +22,7 @@ use super::{ BASIC_KEYWORDS, }; -use crate::clean::{self, ExternalCrate}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate}; use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index eb606178d24..3e7711181f7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -23,7 +23,7 @@ //! These threads are not parallelized (they haven't been a bottleneck yet), and //! both occur before the crate is rendered. -crate mod cache; +crate mod search_index; #[cfg(test)] mod tests; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/search_index.rs similarity index 88% rename from src/librustdoc/html/render/cache.rs rename to src/librustdoc/html/render/search_index.rs index 631eacc9618..0fbe090f219 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,22 +7,12 @@ use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; -use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate}; +use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::markdown::short_markdown_summary; use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; -/// Indicates where an external crate can be found. -crate enum ExternalLocation { - /// Remote URL root of the external crate - Remote(String), - /// This external crate can be found in the local doc/ folder - Local, - /// The external crate could not be found. - Unknown, -} - /// Builds the search index from the collected metadata crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String { let mut defid_to_pathid = FxHashMap::default(); @@ -42,7 +32,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< desc, parent: Some(did), parent_idx: None, - search_type: get_index_search_type(item, tcx, cache), + search_type: get_function_type_for_search(item, tcx), aliases: item.attrs.get_doc_aliases(), }); } @@ -191,15 +181,14 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< ) } -crate fn get_index_search_type<'tcx>( +crate fn get_function_type_for_search<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> Option { let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx, cache), - clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx, cache), - clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx, cache), + clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx), + clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx), + clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx), _ => return None, }; @@ -211,12 +200,12 @@ crate fn get_index_search_type<'tcx>( fn get_index_type(clean_type: &clean::Type, generics: Vec) -> RenderType { RenderType { - name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()), + name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()), generics: if generics.is_empty() { None } else { Some(generics) }, } } -fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { +fn get_index_type_name(clean_type: &clean::Type) -> Option { match *clean_type { clean::Type::Path { ref path, .. } => { let path_segment = path.segments.last().unwrap(); @@ -226,11 +215,10 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option let path = &bounds[0].trait_; Some(path.segments.last().unwrap().name) } - clean::Generic(s) if accept_generic => Some(s), + clean::Generic(s) => Some(s), clean::Primitive(ref p) => Some(p.as_sym()), - clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), - clean::Generic(_) - | clean::BareFunction(_) + clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_), + clean::BareFunction(_) | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) @@ -248,20 +236,19 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option /// /// Important note: It goes through generics recursively. So if you have /// `T: Option>`, it'll go into `Option` and then into `Result`. -crate fn get_real_types<'tcx>( +#[instrument(level = "trace", skip(tcx, res))] +fn add_generics_and_bounds_as_types<'tcx>( generics: &Generics, arg: &Type, tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec, - cache: &Cache, ) { fn insert_ty( res: &mut Vec, tcx: TyCtxt<'_>, ty: Type, mut generics: Vec, - _cache: &Cache, ) { let is_full_generic = ty.is_full_generic(); @@ -330,6 +317,7 @@ crate fn get_real_types<'tcx>( if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed + // See #59502 for the original issue. return; } @@ -350,13 +338,12 @@ crate fn get_real_types<'tcx>( for param_def in poly_trait.generic_params.iter() { match ¶m_def.kind { clean::GenericParamDefKind::Type { default: Some(ty), .. } => { - get_real_types( + add_generics_and_bounds_as_types( generics, ty, tcx, recurse + 1, &mut ty_generics, - cache, ) } _ => {} @@ -364,7 +351,7 @@ crate fn get_real_types<'tcx>( } } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } // Otherwise we check if the trait bounds are "inlined" like `T: Option`... if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { @@ -372,10 +359,16 @@ crate fn get_real_types<'tcx>( for bound in bound.get_bounds().unwrap_or(&[]) { if let Some(path) = bound.get_trait_path() { let ty = Type::Path { path }; - get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache); + add_generics_and_bounds_as_types( + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + ); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } } else { // This is not a type parameter. So for example if we have `T, U: Option`, and we're @@ -386,10 +379,10 @@ crate fn get_real_types<'tcx>( let mut ty_generics = Vec::new(); if let Some(arg_generics) = arg.generics() { for gen in arg_generics.iter() { - get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache); + add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } } @@ -397,19 +390,20 @@ crate fn get_real_types<'tcx>( /// /// i.e. `fn foo>(x: u32, y: B)` will return /// `[u32, Display, Option]`. -crate fn get_all_types<'tcx>( - generics: &Generics, - decl: &FnDecl, +fn get_fn_inputs_and_outputs<'tcx>( + func: &Function, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> (Vec, Vec) { + let decl = &func.decl; + let generics = &func.generics; + let mut all_types = Vec::new(); for arg in decl.inputs.values.iter() { if arg.type_.is_self_type() { continue; } let mut args = Vec::new(); - get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache); + add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args); if !args.is_empty() { all_types.extend(args); } else { @@ -423,7 +417,7 @@ crate fn get_all_types<'tcx>( let mut ret_types = Vec::new(); match decl.output { FnRetTy::Return(ref return_type) => { - get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache); + add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types); if ret_types.is_empty() { if let Some(kind) = return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 0031e3915fa..005da01b52b 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -19,12 +19,11 @@ use rustc_session::Session; use rustdoc_json_types as types; use crate::clean; -use crate::clean::ExternalCrate; +use crate::clean::types::{ExternalCrate, ExternalLocation}; use crate::config::RenderOptions; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; -use crate::html::render::cache::ExternalLocation; use crate::json::conversions::{from_item_id, IntoWithTcx}; #[derive(Clone)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ba355107ed6..10ef92e5f40 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -684,27 +684,36 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns != Namespace::ValueNS { return None; } - debug!("looking for variants or fields named {} for {:?}", item_name, did); + debug!("looking for fields named {} for {:?}", item_name, did); // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) - // NOTE: it's different from variant_field because it resolves fields and variants, + // NOTE: it's different from variant_field because it only resolves struct fields, // not variant fields (2 path segments, not 3). + // + // We need to handle struct (and union) fields in this code because + // syntactically their paths are identical to associated item paths: + // `module::Type::field` and `module::Type::Assoc`. + // + // On the other hand, variant fields can't be mistaken for associated + // items because they look like this: `module::Type::Variant::field`. + // + // Variants themselves don't need to be handled here, even though + // they also look like associated items (`module::Type::Variant`), + // because they are real Rust syntax (unlike the intra-doc links + // field syntax) and are handled by the compiler's resolver. let def = match tcx.type_of(did).kind() { - ty::Adt(def, _) => def, + ty::Adt(def, _) if !def.is_enum() => def, _ => return None, }; - let field = if def.is_enum() { - def.all_fields().find(|item| item.ident.name == item_name) - } else { - def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name) - }?; - let kind = if def.is_enum() { DefKind::Variant } else { DefKind::Field }; - let fragment = if def.is_enum() { - // FIXME: how can the field be a variant? - UrlFragment::Variant(field.ident.name) - } else { - UrlFragment::StructField(field.ident.name) - }; - Some((root_res, fragment, Some((kind, field.did)))) + let field = def + .non_enum_variant() + .fields + .iter() + .find(|item| item.ident.name == item_name)?; + Some(( + root_res, + UrlFragment::StructField(field.ident.name), + Some((DefKind::Field, field.did)), + )) } Res::Def(DefKind::Trait, did) => tcx .associated_items(did) diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs index 0a745e7d34f..6d9cb89f022 100644 --- a/src/test/pretty/attr-fn-inner.rs +++ b/src/test/pretty/attr-fn-inner.rs @@ -9,8 +9,8 @@ fn main() { #![rustc_dummy] #[rustc_dummy] - fn f() { } + fn f() {} #[rustc_dummy] - fn g() { } + fn g() {} } diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index 44d2c5db3e6..d132014420d 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -7,8 +7,8 @@ fn main() { #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] #[rustc_dummy = 8] - fn f() { } + fn f() {} #[rustc_dummy(1, 2, 3)] - fn g() { } + fn g() {} } diff --git a/src/test/pretty/attr-tokens-raw-ident.rs b/src/test/pretty/attr-tokens-raw-ident.rs index bb2c4bb558e..8486342b087 100644 --- a/src/test/pretty/attr-tokens-raw-ident.rs +++ b/src/test/pretty/attr-tokens-raw-ident.rs @@ -4,4 +4,4 @@ // pp-exact #[rustfmt::r#final(final)] -fn main() { } +fn main() {} diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 257c032b536..1137d804564 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -45,4 +45,4 @@ mac! { }] #[rustc_dummy = "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"] -fn main() { } +fn main() {} diff --git a/src/test/pretty/doc-comments.rs b/src/test/pretty/doc-comments.rs index 2a98c9fc058..a49860daa6a 100644 --- a/src/test/pretty/doc-comments.rs +++ b/src/test/pretty/doc-comments.rs @@ -5,7 +5,7 @@ // some single-line non-doc comment /// some single line outer-docs -fn a() { } +fn a() {} fn b() { //! some single line inner-docs @@ -17,7 +17,7 @@ fn b() { ////////////////////////////////// /// some single-line outer-docs preceded by a separator /// (and trailing whitespaces) -fn c() { } +fn c() {} /* * some multi-line non-doc comment @@ -26,7 +26,7 @@ fn c() { } /** * some multi-line outer-docs */ -fn d() { } +fn d() {} fn e() { /*! @@ -43,10 +43,10 @@ fn e() { /** * some multi-line outer-docs preceded by a separator */ -fn f() { } +fn f() {} #[doc = "unsugared outer doc-comments work also"] -fn g() { } +fn g() {} fn h() { #![doc = "as do inner ones"] diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs new file mode 100644 index 00000000000..ce51556dd41 --- /dev/null +++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs @@ -0,0 +1,11 @@ +// check-pass + +// Minimization of issue #59502 + +trait MyTrait { + type Output; +} + +pub fn pow>(arg: T) -> T { + arg +} diff --git a/src/test/ui/error-codes/E0227.rs b/src/test/ui/error-codes/E0227.rs new file mode 100644 index 00000000000..0f0a781d2f9 --- /dev/null +++ b/src/test/ui/error-codes/E0227.rs @@ -0,0 +1,12 @@ +trait Foo<'foo>: 'foo {} +trait Bar<'bar>: 'bar {} + +trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} + +struct Baz<'foo, 'bar> { + baz: dyn FooBar<'foo, 'bar>, + //~^ ERROR ambiguous lifetime bound, explicit lifetime bound required +} + +fn main() { +} diff --git a/src/test/ui/error-codes/E0227.stderr b/src/test/ui/error-codes/E0227.stderr new file mode 100644 index 00000000000..26de5b4c400 --- /dev/null +++ b/src/test/ui/error-codes/E0227.stderr @@ -0,0 +1,9 @@ +error[E0227]: ambiguous lifetime bound, explicit lifetime bound required + --> $DIR/E0227.rs:7:10 + | +LL | baz: dyn FooBar<'foo, 'bar>, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0227`. diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index fcf6a9278d8..90bc7dc1da2 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -235,7 +235,7 @@ fn test_expr() { #[attr] {} ), - "#[attr] { }", // FIXME + "#[attr] {}", ); assert_eq!( stringify_expr!( @@ -803,7 +803,7 @@ fn test_ty() { assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)"); #[rustfmt::skip] assert_eq!(stringify_ty!(for<> fn()), "fn()"); - assert_eq!(stringify_ty!(for<'a> fn()), "for<'a>fn()"); // FIXME + assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()"); // TyKind::Never assert_eq!(stringify_ty!(!), "!"); diff --git a/src/test/ui/match/expr_before_ident_pat.rs b/src/test/ui/match/expr_before_ident_pat.rs new file mode 100644 index 00000000000..47db6c3f488 --- /dev/null +++ b/src/test/ui/match/expr_before_ident_pat.rs @@ -0,0 +1,15 @@ +#![feature(half_open_range_patterns)] + +macro_rules! funny { + ($a:expr, $b:ident) => { + match [1, 2] { + [$a, $b] => {} + } + }; +} + +fn main() { + funny!(a, a); + //~^ ERROR cannot find value `a` in this scope + //~| ERROR arbitrary expressions aren't allowed in patterns +} diff --git a/src/test/ui/match/expr_before_ident_pat.stderr b/src/test/ui/match/expr_before_ident_pat.stderr new file mode 100644 index 00000000000..1ac8274ffd5 --- /dev/null +++ b/src/test/ui/match/expr_before_ident_pat.stderr @@ -0,0 +1,15 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/expr_before_ident_pat.rs:12:12 + | +LL | funny!(a, a); + | ^ + +error[E0425]: cannot find value `a` in this scope + --> $DIR/expr_before_ident_pat.rs:12:12 + | +LL | funny!(a, a); + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/match/issue-92100.rs b/src/test/ui/match/issue-92100.rs new file mode 100644 index 00000000000..021166b2ba5 --- /dev/null +++ b/src/test/ui/match/issue-92100.rs @@ -0,0 +1,7 @@ +#![feature(half_open_range_patterns)] + +fn main() { + match [1, 2] { + [a.., a] => {} //~ ERROR cannot find value `a` in this scope + } +} diff --git a/src/test/ui/match/issue-92100.stderr b/src/test/ui/match/issue-92100.stderr new file mode 100644 index 00000000000..0f694c587fc --- /dev/null +++ b/src/test/ui/match/issue-92100.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `a` in this scope + --> $DIR/issue-92100.rs:5:10 + | +LL | [a.., a] => {} + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs new file mode 100644 index 00000000000..a9fa23dd95e --- /dev/null +++ b/src/test/ui/parser/type-alias-where.rs @@ -0,0 +1,37 @@ +// check-fail + +#![feature(generic_associated_types)] + +// Fine, but lints as unused +type Foo where u32: Copy = (); +// Not fine. +type Bar = () where u32: Copy; +//~^ ERROR where clause not allowed here +type Baz = () where; +//~^ ERROR where clause not allowed here + +trait Trait { + // Fine. + type Assoc where u32: Copy; + // Fine. + type Assoc2 where u32: Copy, i32: Copy; +} + +impl Trait for u32 { + // Fine. + type Assoc where u32: Copy = (); + // Not fine, suggests moving `i32: Copy` + type Assoc2 where u32: Copy = () where i32: Copy; + //~^ ERROR where clause not allowed here +} + +impl Trait for i32 { + // Not fine, suggests moving `u32: Copy` + type Assoc = () where u32: Copy; + //~^ ERROR where clause not allowed here + // Not fine, suggests moving both. + type Assoc2 = () where u32: Copy, i32: Copy; + //~^ ERROR where clause not allowed here +} + +fn main() {} diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr new file mode 100644 index 00000000000..7ab0b28c864 --- /dev/null +++ b/src/test/ui/parser/type-alias-where.stderr @@ -0,0 +1,40 @@ +error: where clause not allowed here + --> $DIR/type-alias-where.rs:8:15 + | +LL | type Bar = () where u32: Copy; + | - ^^^^^^^^^^^^^^^ + | | + | help: move it here: `where u32: Copy` + +error: where clause not allowed here + --> $DIR/type-alias-where.rs:10:15 + | +LL | type Baz = () where; + | ^^^^^ + +error: where clause not allowed here + --> $DIR/type-alias-where.rs:24:38 + | +LL | type Assoc2 where u32: Copy = () where i32: Copy; + | - ^^^^^^^^^^^^^^^ + | | + | help: move it here: `, i32: Copy` + +error: where clause not allowed here + --> $DIR/type-alias-where.rs:30:21 + | +LL | type Assoc = () where u32: Copy; + | - ^^^^^^^^^^^^^^^ + | | + | help: move it here: `where u32: Copy` + +error: where clause not allowed here + --> $DIR/type-alias-where.rs:33:22 + | +LL | type Assoc2 = () where u32: Copy, i32: Copy; + | - ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: move it here: `where u32: Copy, i32: Copy` + +error: aborting due to 5 previous errors + diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 6d3e470bf43..8ea6bb308b7 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -10,8 +10,8 @@ use regex::Regex; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ - "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", - "E0519", "E0523", "E0554", "E0640", "E0717", "E0729", + "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519", + "E0523", "E0554", "E0640", "E0717", "E0729", ]; // Some error codes don't have any tests apparently...