diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 71cacfe370658..501ef01d74c6e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -696,7 +696,7 @@ impl DepGraph { // Promote the previous diagnostics to the current session. tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone()); + .store_diagnostics(dep_node_index, diagnostics.clone().into()); for diagnostic in diagnostics { DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 4cce8343c02c8..f71cce8273c46 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -487,6 +487,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) { match cause.code { + ObligationCauseCode::MatchExpressionArmPattern { span, ty } => { + if ty.is_suggestable() { // don't show type `_` + err.span_label(span, format!("this match expression has type `{}`", ty)); + } + } ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arm with an incompatible type"; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7ce5960b9b3d6..7d9e80fd60f5c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1444,6 +1444,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *cause_code { ObligationCauseCode::ExprAssignable | ObligationCauseCode::MatchExpressionArm { .. } | + ObligationCauseCode::MatchExpressionArmPattern { .. } | ObligationCauseCode::IfExpression | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType | @@ -1451,8 +1452,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | - ObligationCauseCode::MiscObligation => { - } + ObligationCauseCode::MiscObligation => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index b42d742b7f841..14c25b77a1b82 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -220,8 +220,13 @@ pub enum ObligationCauseCode<'tcx> { ExprAssignable, /// Computing common supertype in the arms of a match expression - MatchExpressionArm { arm_span: Span, - source: hir::MatchSource }, + MatchExpressionArm { + arm_span: Span, + source: hir::MatchSource, + }, + + /// Computing common supertype in the pattern guard for the arms of a match expression + MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> }, /// Computing common supertype in an if expression IfExpression, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index ae2b83e105773..277e2ed0e87d2 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -517,6 +517,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { arm_span, source: source, }), + super::MatchExpressionArmPattern { span, ty } => { + tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) + } super::IfExpression => Some(super::IfExpression), super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), super::MainFunctionType => Some(super::MainFunctionType), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 032a1621fe60b..d69219efbd884 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1682,6 +1682,7 @@ impl<'gcx> GlobalCtxt<'gcx> { let new_icx = ty::tls::ImplicitCtxt { tcx, query: icx.query.clone(), + diagnostics: icx.diagnostics, layout_depth: icx.layout_depth, task_deps: icx.task_deps, }; @@ -1792,6 +1793,7 @@ pub mod tls { use errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_data_structures::OnDrop; use rustc_data_structures::sync::{self, Lrc, Lock}; + use rustc_data_structures::thin_vec::ThinVec; use dep_graph::TaskDeps; #[cfg(not(parallel_queries))] @@ -1811,10 +1813,14 @@ pub mod tls { /// by `enter_local` with a new local interner pub tcx: TyCtxt<'tcx, 'gcx, 'tcx>, - /// The current query job, if any. This is updated by start_job in + /// The current query job, if any. This is updated by JobOwner::start in /// ty::query::plumbing when executing a query pub query: Option>>, + /// Where to store diagnostics for the current query job, if any. + /// This is updated by JobOwner::start in ty::query::plumbing when executing a query + pub diagnostics: Option<&'a Lock>>, + /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, @@ -1880,8 +1886,9 @@ pub mod tls { fn track_diagnostic(diagnostic: &Diagnostic) { with_context_opt(|icx| { if let Some(icx) = icx { - if let Some(ref query) = icx.query { - query.diagnostics.lock().push(diagnostic.clone()); + if let Some(ref diagnostics) = icx.diagnostics { + let mut diagnostics = diagnostics.lock(); + diagnostics.extend(Some(diagnostic.clone())); } } }) @@ -1948,6 +1955,7 @@ pub mod tls { let icx = ImplicitCtxt { tcx, query: None, + diagnostics: None, layout_depth: 0, task_deps: None, }; @@ -1977,6 +1985,7 @@ pub mod tls { }; let icx = ImplicitCtxt { query: None, + diagnostics: None, tcx, layout_depth: 0, task_deps: None, diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 0063794727fd2..d794429a8a706 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -14,7 +14,6 @@ use ty::query::{ config::QueryDescription, }; use ty::context::TyCtxt; -use errors::Diagnostic; use std::process; use std::{fmt, ptr}; @@ -54,9 +53,6 @@ pub struct QueryJob<'tcx> { /// The parent query job which created this job and is implicitly waiting on it. pub parent: Option>>, - /// Diagnostic messages which are emitted while the query executes - pub diagnostics: Lock>, - /// The latch which is used to wait on this job #[cfg(parallel_queries)] latch: QueryLatch<'tcx>, @@ -66,7 +62,6 @@ impl<'tcx> QueryJob<'tcx> { /// Creates a new query job pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { QueryJob { - diagnostics: Lock::new(Vec::new()), info, parent, #[cfg(parallel_queries)] diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 3432aba7ee0d0..a674e942b3893 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -7,6 +7,7 @@ use ich::{CachingSourceMapView, Fingerprint}; use mir::{self, interpret}; use mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, @@ -341,11 +342,13 @@ impl<'sess> OnDiskCache<'sess> { /// Store a diagnostic emitted during the current compilation session. /// Anything stored like this will be available via `load_diagnostics` in /// the next compilation session. + #[inline(never)] + #[cold] pub fn store_diagnostics(&self, dep_node_index: DepNodeIndex, - diagnostics: Vec) { + diagnostics: ThinVec) { let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - let prev = current_diagnostics.insert(dep_node_index, diagnostics); + let prev = current_diagnostics.insert(dep_node_index, diagnostics.into()); debug_assert!(prev.is_none()); } @@ -367,16 +370,16 @@ impl<'sess> OnDiskCache<'sess> { /// Since many anonymous queries can share the same `DepNode`, we aggregate /// them -- as opposed to regular queries where we assume that there is a /// 1:1 relationship between query-key and `DepNode`. + #[inline(never)] + #[cold] pub fn store_diagnostics_for_anon_node(&self, dep_node_index: DepNodeIndex, - mut diagnostics: Vec) { + diagnostics: ThinVec) { let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| { - mem::replace(&mut diagnostics, Vec::new()) - }); + let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new()); - x.extend(diagnostics.into_iter()); + x.extend(Into::>::into(diagnostics)); } fn load_indexed<'tcx, T>(&self, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index af23bf3c5901f..32d4070dfed2a 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -18,6 +18,7 @@ use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; use rustc_data_structures::fx::{FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::thin_vec::ThinVec; use std::mem; use std::ptr; use std::collections::hash_map::Entry; @@ -195,19 +196,21 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { pub(super) fn start<'lcx, F, R>( &self, tcx: TyCtxt<'_, 'tcx, 'lcx>, + diagnostics: Option<&Lock>>, compute: F) - -> (R, Vec) + -> R where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R { // The TyCtxt stored in TLS has the same global interner lifetime // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes // when accessing the ImplicitCtxt - let r = tls::with_related_context(tcx, move |current_icx| { + tls::with_related_context(tcx, move |current_icx| { // Update the ImplicitCtxt to point to our new query job let new_icx = tls::ImplicitCtxt { tcx: tcx.global_tcx(), query: Some(self.job.clone()), + diagnostics, layout_depth: current_icx.layout_depth, task_deps: current_icx.task_deps, }; @@ -216,13 +219,19 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { tls::enter_context(&new_icx, |_| { compute(tcx) }) - }); + }) + } - // Extract the diagnostic from the job - let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new()); +} - (r, diagnostics) - } +#[inline(always)] +fn with_diagnostics(f: F) -> (R, ThinVec) +where + F: FnOnce(Option<&Lock>>) -> R +{ + let diagnostics = Lock::new(ThinVec::new()); + let result = f(Some(&diagnostics)); + (result, diagnostics.into_inner()) } impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { @@ -402,20 +411,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { profq_msg!(self, ProfileQueriesMsg::ProviderBegin); self.sess.profiler(|p| p.start_activity(Q::CATEGORY)); - let res = job.start(self, |tcx| { - tcx.dep_graph.with_anon_task(dep_node.kind, || { - Q::compute(tcx.global_tcx(), key) + let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { + job.start(self, diagnostics, |tcx| { + tcx.dep_graph.with_anon_task(dep_node.kind, || { + Q::compute(tcx.global_tcx(), key) + }) }) }); self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - let ((result, dep_node_index), diagnostics) = res; self.dep_graph.read_index(dep_node_index); - self.queries.on_disk_cache - .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + if unlikely!(!diagnostics.is_empty()) { + self.queries.on_disk_cache + .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + } job.complete(&result, dep_node_index); @@ -487,7 +499,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The diagnostics for this query have already been // promoted to the current session during // try_mark_green(), so we can ignore them here. - let (result, _) = job.start(self, |tcx| { + let result = job.start(self, None, |tcx| { // The dep-graph for this computation is already in // place tcx.dep_graph.with_ignore(|| { @@ -566,32 +578,34 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { profq_msg!(self, ProfileQueriesMsg::ProviderBegin); self.sess.profiler(|p| p.start_activity(Q::CATEGORY)); - let res = job.start(self, |tcx| { - if dep_node.kind.is_eval_always() { - tcx.dep_graph.with_eval_always_task(dep_node, - tcx, - key, - Q::compute) - } else { - tcx.dep_graph.with_task(dep_node, - tcx, - key, - Q::compute) - } + let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { + job.start(self, diagnostics, |tcx| { + if dep_node.kind.is_eval_always() { + tcx.dep_graph.with_eval_always_task(dep_node, + tcx, + key, + Q::compute) + } else { + tcx.dep_graph.with_task(dep_node, + tcx, + key, + Q::compute) + } + }) }); self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - let ((result, dep_node_index), diagnostics) = res; - if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { self.dep_graph.mark_loaded_from_cache(dep_node_index, false); } if dep_node.kind != ::dep_graph::DepKind::Null { - self.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics); + if unlikely!(!diagnostics.is_empty()) { + self.queries.on_disk_cache + .store_diagnostics(dep_node_index, diagnostics); + } } job.complete(&result, dep_node_index); diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index b25d47b390175..188a112044298 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1372,7 +1372,14 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); if is_visible { - field.ty(cx.tcx, substs) + let ty = field.ty(cx.tcx, substs); + match ty.sty { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) if len.assert_usize(cx.tcx).is_none() => + cx.tcx.types.err, + _ => ty, + } } else { // Treat all non-visible fields as TyErr. They // can't appear in any other pattern from diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b66c383edb51e..1767af4870d3b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -20,21 +20,33 @@ use std::cmp; use super::report_unexpected_variant_def; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - /// The `is_arg` argument indicates whether this pattern is the - /// *outermost* pattern in an argument (e.g., in `fn foo(&x: - /// &u32)`, it is true for the `&x` pattern but not `x`). This is - /// used to tailor error reporting. + /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of + /// a match expression arm guard, and it points to the match discriminant to add context + /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the + /// `a + b` expression: + /// + /// ```text + /// error[E0308]: mismatched types + /// --> src/main.rs:5:9 + /// | + /// 4 | let temp: usize = match a + b { + /// | ----- this expression has type `usize` + /// 5 | Ok(num) => num, + /// | ^^^^^^^ expected usize, found enum `std::result::Result` + /// | + /// = note: expected type `usize` + /// found type `std::result::Result<_, _>` + /// ``` pub fn check_pat_walk( &self, pat: &'gcx hir::Pat, mut expected: Ty<'tcx>, mut def_bm: ty::BindingMode, - is_arg: bool) - { + match_discrim_span: Option, + ) { let tcx = self.tcx; - debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})", - pat, expected, def_bm, is_arg); + debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); let is_non_ref_pat = match pat.node { PatKind::Struct(..) | @@ -210,8 +222,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let common_type = self.resolve_type_vars_if_possible(&lhs_ty); // subtyping doesn't matter here, as the value is some kind of scalar - self.demand_eqtype(pat.span, expected, lhs_ty); - self.demand_eqtype(pat.span, expected, rhs_ty); + self.demand_eqtype_pat(pat.span, expected, lhs_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, rhs_ty, match_discrim_span); common_type } PatKind::Binding(ba, var_id, _, ref sub) => { @@ -240,13 +252,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for // an explanation. - self.demand_eqtype(pat.span, region_ty, local_ty); + self.demand_eqtype_pat(pat.span, region_ty, local_ty, match_discrim_span); } // otherwise the type of x is the expected type T ty::BindByValue(_) => { // As above, `T <: typeof(x)` is required but we // use equality, see (*) below. - self.demand_eqtype(pat.span, expected, local_ty); + self.demand_eqtype_pat(pat.span, expected, local_ty, match_discrim_span); } } @@ -254,23 +266,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // what the type of the binding `x` ought to be if var_id != pat.id { let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype(pat.span, vt, local_ty); + self.demand_eqtype_pat(pat.span, vt, local_ty, match_discrim_span); } if let Some(ref p) = *sub { - self.check_pat_walk(&p, expected, def_bm, true); + self.check_pat_walk(&p, expected, def_bm, match_discrim_span); } local_ty } PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { - self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm) + self.check_pat_tuple_struct( + pat, + qpath, + &subpats, + ddpos, + expected, + def_bm, + match_discrim_span, + ) } PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, expected) } PatKind::Struct(ref qpath, ref fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm) + self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, match_discrim_span) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -295,12 +315,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.types.err); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &tcx.types.err, def_bm, true); + self.check_pat_walk(elem, &tcx.types.err, def_bm, match_discrim_span); } tcx.mk_tup(element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &element_tys[i], def_bm, true); + self.check_pat_walk(elem, &element_tys[i], def_bm, match_discrim_span); } pat_ty } @@ -313,11 +333,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using // `demand::eqtype`. - self.demand_eqtype(pat.span, expected, uniq_ty); - self.check_pat_walk(&inner, inner_ty, def_bm, true); + self.demand_eqtype_pat(pat.span, expected, uniq_ty, match_discrim_span); + self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); uniq_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, true); + self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); tcx.types.err } } @@ -349,15 +369,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - if is_arg { - if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) - { - err.help(&format!("did you mean `{}: &{}`?", - &snippet[1..], - expected)); - } + if let PatKind::Binding(..) = inner.node { + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(pat.span) + { + err.help(&format!("did you mean `{}: &{}`?", + &snippet[1..], + expected)); } } err.emit(); @@ -366,10 +384,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.check_pat_walk(&inner, inner_ty, def_bm, true); + self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); rptr_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, true); + self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); tcx.types.err } } @@ -427,13 +445,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; for elt in before { - self.check_pat_walk(&elt, inner_ty, def_bm, true); + self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); } if let Some(ref slice) = *slice { - self.check_pat_walk(&slice, slice_ty, def_bm, true); + self.check_pat_walk(&slice, slice_ty, def_bm, match_discrim_span); } for elt in after { - self.check_pat_walk(&elt, inner_ty, def_bm, true); + self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); } expected_ty } @@ -524,12 +542,14 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); true } - pub fn check_match(&self, - expr: &'gcx hir::Expr, - discrim: &'gcx hir::Expr, - arms: &'gcx [hir::Arm], - expected: Expectation<'tcx>, - match_src: hir::MatchSource) -> Ty<'tcx> { + pub fn check_match( + &self, + expr: &'gcx hir::Expr, + discrim: &'gcx hir::Expr, + arms: &'gcx [hir::Arm], + expected: Expectation<'tcx>, + match_src: hir::MatchSource, + ) -> Ty<'tcx> { let tcx = self.tcx; // Not entirely obvious: if matches may create ref bindings, we want to @@ -624,8 +644,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { self.diverges.set(Diverges::Maybe); - self.check_pat_walk(&p, discrim_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true); + self.check_pat_walk( + &p, + discrim_ty, + ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), + Some(discrim.span), + ); all_pats_diverge &= self.diverges.get(); } @@ -703,26 +727,34 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); coercion.complete(self) } - fn check_pat_struct(&self, - pat: &'gcx hir::Pat, - qpath: &hir::QPath, - fields: &'gcx [Spanned], - etc: bool, - expected: Ty<'tcx>, - def_bm: ty::BindingMode) -> Ty<'tcx> + fn check_pat_struct( + &self, + pat: &'gcx hir::Pat, + qpath: &hir::QPath, + fields: &'gcx [Spanned], + etc: bool, + expected: Ty<'tcx>, + def_bm: ty::BindingMode, + match_discrim_span: Option, + ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) { variant_ty } else { for field in fields { - self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, true); + self.check_pat_walk( + &field.node.pat, + self.tcx.types.err, + def_bm, + match_discrim_span, + ); } return self.tcx.types.err; }; // Type-check the path. - self.demand_eqtype(pat.span, expected, pat_ty); + self.demand_eqtype_pat(pat.span, expected, pat_ty, match_discrim_span); // Type-check subpatterns. if self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm) { @@ -732,11 +764,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } } - fn check_pat_path(&self, - pat: &hir::Pat, - qpath: &hir::QPath, - expected: Ty<'tcx>) -> Ty<'tcx> - { + fn check_pat_path( + &self, + pat: &hir::Pat, + qpath: &hir::QPath, + expected: Ty<'tcx>, + ) -> Ty<'tcx> { let tcx = self.tcx; // Resolve the path and check the definition for errors. @@ -767,18 +800,20 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); pat_ty } - fn check_pat_tuple_struct(&self, - pat: &hir::Pat, - qpath: &hir::QPath, - subpats: &'gcx [P], - ddpos: Option, - expected: Ty<'tcx>, - def_bm: ty::BindingMode) -> Ty<'tcx> - { + fn check_pat_tuple_struct( + &self, + pat: &hir::Pat, + qpath: &hir::QPath, + subpats: &'gcx [P], + ddpos: Option, + expected: Ty<'tcx>, + def_bm: ty::BindingMode, + match_arm_pat_span: Option, + ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = || { for pat in subpats { - self.check_pat_walk(&pat, tcx.types.err, def_bm, true); + self.check_pat_walk(&pat, tcx.types.err, def_bm, match_arm_pat_span); } }; let report_unexpected_def = |def: Def| { @@ -826,7 +861,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let pat_ty = pat_ty.fn_sig(tcx).output(); let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); - self.demand_eqtype(pat.span, expected, pat_ty); + self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span); // Type-check subpatterns. if subpats.len() == variant.fields.len() || @@ -837,7 +872,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat_walk(&subpat, field_ty, def_bm, true); + self.check_pat_walk(&subpat, field_ty, def_bm, match_arm_pat_span); self.tcx.check_stability(variant.fields[i].did, Some(pat.id), subpat.span); } @@ -917,7 +952,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } }; - self.check_pat_walk(&field.pat, field_ty, def_bm, true); + self.check_pat_walk(&field.pat, field_ty, def_bm, None); } let mut unmentioned_fields = variant.fields .iter() diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 41f2b0ec7d24e..c0cedd77440d9 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,6 +1,6 @@ use check::FnCtxt; use rustc::infer::InferOk; -use rustc::traits::ObligationCause; +use rustc::traits::{ObligationCause, ObligationCauseCode}; use syntax::ast; use syntax::util::parser::PREC_POSTFIX; @@ -66,6 +66,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn demand_eqtype_pat( + &self, + cause_span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + match_expr_span: Option, + ) { + let cause = if let Some(span) = match_expr_span { + self.cause( + cause_span, + ObligationCauseCode::MatchExpressionArmPattern { span, ty: expected }, + ) + } else { + self.misc(cause_span) + }; + self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit()); + } + + pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8790d718f53f0..dbbb7f42feb24 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1092,8 +1092,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { // Check the pattern. - fcx.check_pat_walk(&arg.pat, arg_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true); + fcx.check_pat_walk( + &arg.pat, + arg_ty, + ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), + None, + ); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings @@ -4731,9 +4735,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - self.check_pat_walk(&local.pat, t, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - true); + self.check_pat_walk( + &local.pat, + t, + ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), + None, + ); let pat_ty = self.node_ty(local.pat.hir_id); if pat_ty.references_error() { self.write_ty(local.hir_id, pat_ty); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b48951d7593b6..31e06cb1a045f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3059,7 +3059,7 @@ fn item_trait( let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "{extra}

", + write!(w, "

{extra}", extra = render_spotlight_traits(m)?, id = id, ns_id = ns_id)?; @@ -3444,7 +3444,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, let id = format!("{}.{}", ItemType::StructField, name); write!(w, "\ \ - \ + {name}: {ty}\ ", id = id, name = name, @@ -3999,8 +3999,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi None => "impl".to_string(), }); if let Some(use_absolute) = use_absolute { - write!(w, "

\ -
", id)?; + write!(w, "

", id)?; fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute)?; if show_def_docs { for it in &i.inner_impl().items { @@ -4014,22 +4013,18 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } write!(w, "")?; } else { - write!(w, "

\ -
{}", - id, i.inner_impl())?; + write!(w, "

{}", + id, i.inner_impl() + )?; } write!(w, "", id)?; - write!(w, "

")?; let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); + render_stability_since_raw(w, since, outer_version)?; if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() { - write!(w, "
")?; - render_stability_since_raw(w, since, outer_version)?; write!(w, "[src]", l, "goto source code")?; - } else { - render_stability_since_raw(w, since, outer_version)?; } - write!(w, "

")?; + write!(w, "")?; if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", @@ -4065,20 +4060,15 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "{}", spotlight_decl(decl)?)?; - write!(w, "
", ns_id)?; + write!(w, "", ns_id)?; render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?; write!(w, "")?; + render_stability_since_raw(w, item.stable_since(), outer_version)?; if let Some(l) = (Item { cx, item }).src_href() { - write!(w, "")?; - write!(w, "
")?; - render_stability_since_raw(w, item.stable_since(), outer_version)?; - write!(w, "[src]
", + write!(w, "[src]", l, "goto source code")?; - } else { - write!(w, "
")?; - render_stability_since_raw(w, item.stable_since(), outer_version)?; } - write!(w, "

")?; + write!(w, "")?; } } clean::TypedefItem(ref tydef, _) => { @@ -4090,40 +4080,18 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
")?; } clean::AssociatedConstItem(ref ty, ref default) => { - let mut version = String::new(); - - render_stability_since_raw(&mut version, item.stable_since(), outer_version)?; - let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; - if !version.is_empty() { - write!(w, "
", ns_id)?; - } else { - write!(w, "", ns_id)?; - } + write!(w, "", ns_id)?; assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?; - if !version.is_empty() { - write!(w, "")?; - } - let src = if let Some(l) = (Item { cx, item }).src_href() { - if !version.is_empty() { - write!(w, "")?; - write!(w, "
{}", version)?; - } - format!("[src]", - l, "goto source code") - } else { - if !version.is_empty() { - write!(w, "
{}", version)?; - } - String::new() - }; - if version.is_empty() { - write!(w, "{}", src)?; - } else { - write!(w, "{}

", src)?; + write!(w, "")?; + render_stability_since_raw(w, item.stable_since(), outer_version)?; + if let Some(l) = (Item { cx, item }).src_href() { + write!(w, "[src]", + l, "goto source code")?; } + write!(w, "")?; } clean::AssociatedTypeItem(ref bounds, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 75b0f5df0d8b3..9db1c68609039 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2409,8 +2409,17 @@ if (!DOMTokenList.prototype.remove) { e.remove(); }); onEachLazy(main.childNodes, function(e) { + // Unhide the actual content once loading is complete. Headers get + // flex treatment for their horizontal layout, divs get block treatment + // for vertical layout (column-oriented flex layout for divs caused + // errors in mobile browsers). if (e.tagName === "H2" || e.tagName === "H3") { - e.nextElementSibling.style.display = "block"; + let nextTagName = e.nextElementSibling.tagName; + if (nextTagName == "H2" || nextTagName == "H3") { + e.nextElementSibling.style.display = "flex"; + } else { + e.nextElementSibling.style.display = "block"; + } } }); } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 14273c6b1db33..8a8b7adcf7d4a 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -89,8 +89,9 @@ h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.t border-bottom: 1px solid; } h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant { + flex-basis: 100%; font-weight: 600; - margin-top: 10px; + margin-top: 16px; margin-bottom: 10px; position: relative; } @@ -356,7 +357,8 @@ nav.sub { #main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; } #main > h2 + div, #main > h2 + h3, #main > h3 + div { - display: none; + display: none; /* Changed to flex or block via js once the page is loaded */ + flex-wrap: wrap; } .docblock h1 { font-size: 1em; } @@ -390,7 +392,7 @@ h4 > code, h3 > code, .invisible > code { } .in-band, code { - z-index: 5; + z-index: -5; } .invisible { @@ -534,6 +536,10 @@ h4 > code, h3 > code, .invisible > code { margin-top: -8px; } +.impl-items { + flex-basis: 100%; +} + #main > .stability { margin-top: 0; } @@ -784,6 +790,33 @@ body.blur > :not(#help) { top: 0; } +.impl-items .since, .impl .since { + flex-grow: 0; + padding-left: 12px; + padding-right: 2px; + position: initial; +} + +.impl-items .srclink, .impl .srclink { + flex-grow: 0; + /* Override header settings otherwise it's too bold */ + font-size: 17px; + font-weight: normal; +} + +.impl-items code, .impl code { + flex-grow: 1; +} + +.impl-items h4, h4.impl, h3.impl { + display: flex; + flex-basis: 100%; + font-size: 16px; + margin-bottom: 12px; + /* Push the src link out to the right edge consistently */ + justify-content: space-between; +} + .variants_table { width: 100%; } @@ -871,15 +904,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { margin-left: 20px; } -.ghost { - display: none; -} - -.ghost + .since { - position: initial; - display: table-cell; -} - .since + .srclink { display: table-cell; padding-left: 10px; @@ -1119,7 +1143,7 @@ span.since { margin-left: 5px; top: -5px; left: 105%; - z-index: 1; + z-index: 10; } .tooltip:hover .tooltiptext { @@ -1361,8 +1385,9 @@ h3.important { margin-top: 16px; } -.content > .methods > div.important-traits { +.content > .methods > .method > div.important-traits { position: absolute; + font-weight: 400; left: -42px; margin-top: 2px; } diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs index 3f3c25162994e..c561269cf9a85 100644 --- a/src/test/rustdoc/assoc-consts-version.rs +++ b/src/test/rustdoc/assoc-consts-version.rs @@ -10,7 +10,7 @@ pub struct SomeStruct; impl SomeStruct { - // @has 'foo/struct.SomeStruct.html' '//*[@id="SOME_CONST.v"]//div[@class="since"]' '1.1.2' + // @has 'foo/struct.SomeStruct.html' '//*[@id="associatedconstant.SOME_CONST"]//div[@class="since"]' '1.1.2' #[stable(since="1.1.2", feature="rust2")] pub const SOME_CONST: usize = 0; } diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs index f3118bb606630..c33db5809cc7c 100644 --- a/src/test/rustdoc/const.rs +++ b/src/test/rustdoc/const.rs @@ -3,7 +3,7 @@ pub struct Foo; impl Foo { - // @has const/struct.Foo.html '//*[@id="new.v"]//code' 'const unsafe fn new' + // @has const/struct.Foo.html '//code[@id="new.v"]' 'const unsafe fn new' pub const unsafe fn new() -> Foo { Foo } diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs index 3c1580f3786bb..55d8ee394385b 100644 --- a/src/test/rustdoc/issue-25001.rs +++ b/src/test/rustdoc/issue-25001.rs @@ -9,17 +9,17 @@ pub trait Bar { impl Foo { // @has - '//*[@id="method.pass"]//code' 'fn pass()' - // @has - '//*[@id="pass.v"]//code' 'fn pass()' + // @has - '//code[@id="pass.v"]' 'fn pass()' pub fn pass() {} } impl Foo { // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize' - // @has - '//*[@id="pass.v-1"]//code' 'fn pass() -> usize' + // @has - '//code[@id="pass.v-1"]' 'fn pass() -> usize' pub fn pass() -> usize { 42 } } impl Foo { // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize' - // @has - '//*[@id="pass.v-2"]//code' 'fn pass() -> isize' + // @has - '//code[@id="pass.v-2"]' 'fn pass() -> isize' pub fn pass() -> isize { 42 } } diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs index b57a067f3d9b8..d9accf9c5998b 100644 --- a/src/test/rustdoc/issue-51236.rs +++ b/src/test/rustdoc/issue-51236.rs @@ -7,7 +7,7 @@ pub mod traits { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl Send for \ // Owned where >::Reader: Send" pub struct Owned where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<>::Reader>, diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs index 34f71fab0cc63..263b1eb0bd65a 100644 --- a/src/test/rustdoc/issue-54705.rs +++ b/src/test/rustdoc/issue-54705.rs @@ -3,10 +3,10 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'scope, S> \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \ // Send for ScopeFutureContents<'scope, S> where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'scope, S> \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \ // Sync for ScopeFutureContents<'scope, S> where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs index 5c34a4d34ab87..257cb32c65c25 100644 --- a/src/test/rustdoc/issue-55321.rs +++ b/src/test/rustdoc/issue-55321.rs @@ -1,16 +1,16 @@ #![feature(optin_builtin_traits)] // @has issue_55321/struct.A.html -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' "impl !Send for A" -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' "impl !Sync for A" +// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Send for A" +// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Sync for A" pub struct A(); impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl !Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl !Send for \ // B" -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl !Sync for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl !Sync for \ // B" pub struct B(A, Box); diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs index 2d6cb1368d120..5b67817fa4caa 100644 --- a/src/test/rustdoc/issue-56822.rs +++ b/src/test/rustdoc/issue-56822.rs @@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'a> Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a> Send for \ // Parser<'a>" pub struct Parser<'a> { field: > as MyTrait>::Output diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index d2533a2dd390e..609cefc7115e2 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -20,7 +20,7 @@ mod foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'a, T, K: \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a, T, K: \ // ?Sized> Send for NotOuter<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, >::MyItem: Copy, 'a: 'static" diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs index 03b84c7838edc..6d0a68f9b0734 100644 --- a/src/test/rustdoc/synthetic_auto/lifetimes.rs +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -9,10 +9,10 @@ where {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Send \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \ // for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Sync \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \ // for Foo<'c, K> where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index c7cfa0c0fa1b8..413ba187f4556 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -1,8 +1,8 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' 'impl Sync for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl Sync for \ // Foo where T: Sync' // -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' \ +// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' \ // 'impl Send for Foo' // // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs index 5b6304ed4e471..30713849da221 100644 --- a/src/test/rustdoc/synthetic_auto/negative.rs +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -3,10 +3,10 @@ pub struct Inner { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl !Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl !Send for \ // Outer" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl \ // !Sync for Outer" pub struct Outer { inner_field: Inner, diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs index 75d2ff2af13e1..e710ce1c2ed95 100644 --- a/src/test/rustdoc/synthetic_auto/nested.rs +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' 'impl Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl Send for \ // Foo where T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' \ // 'impl Sync for Foo where T: Sync' pub struct Foo { inner_field: Inner, diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index 92402714b9d51..cf173111ec1e2 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,7 +9,7 @@ where } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl Send for \ // Outer where T: Copy + Send" pub struct Outer { inner_field: Inner, diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs index 6be6b44a4400a..5346521f8d2e3 100644 --- a/src/test/rustdoc/synthetic_auto/project.rs +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -23,10 +23,10 @@ where } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Send \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \ // for Foo<'c, K> where K: MyTrait, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Sync \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \ // for Foo<'c, K> where K: MyTrait, ::MyItem: OtherTrait, 'c: 'static," pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index 0dca8fe297820..7d15434afe6db 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl Pattern for Wrapper { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl Send for \ // WriteAndThen where ::Value: Send" pub struct WriteAndThen(pub P1::Value,pub > as Pattern>::Value) where P1: Pattern; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs index d1d50fbc6ba15..59493744b623d 100644 --- a/src/test/rustdoc/synthetic_auto/static-region.rs +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl Send for \ // Owned where >::Reader: Send" pub struct Owned where T: OwnedTrait<'static> { marker: >::Reader, diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr index b38633b0ffeea..417667a5354fd 100644 --- a/src/test/ui/block-result/issue-13624.stderr +++ b/src/test/ui/block-result/issue-13624.stderr @@ -12,6 +12,8 @@ LL | Enum::EnumStructVariant { x: 1, y: 2, z: 3 } error[E0308]: mismatched types --> $DIR/issue-13624.rs:22:9 | +LL | match enum_struct_variant { + | ------------------- this match expression has type `()` LL | a::Enum::EnumStructVariant { x, y, z } => { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum` | diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index 8117bc754b6b9..f69a389336590 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/E0308-4.rs:4:9 | +LL | match x { + | - this match expression has type `u8` LL | 0u8..=3i8 => (), //~ ERROR E0308 | ^^^^^^^^^ expected u8, found i8 diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr index 05d2685958eb8..683ad48ff52c0 100644 --- a/src/test/ui/issues/issue-11844.stderr +++ b/src/test/ui/issues/issue-11844.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-11844.rs:6:9 | +LL | match a { + | - this match expression has type `std::option::Option>` LL | Ok(a) => //~ ERROR: mismatched types | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index ca5efcdc4726a..768d11bf899a1 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-12552.rs:6:5 | +LL | match t { + | - this match expression has type `std::result::Result<_, {integer}>` LL | Some(k) => match k { //~ ERROR mismatched types | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr index 2f60070337b77..66255891f469a 100644 --- a/src/test/ui/issues/issue-13466.stderr +++ b/src/test/ui/issues/issue-13466.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-13466.rs:8:9 | +LL | let _x: usize = match Some(1) { + | ------- this match expression has type `std::option::Option<{integer}>` LL | Ok(u) => u, | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | @@ -10,6 +12,9 @@ LL | Ok(u) => u, error[E0308]: mismatched types --> $DIR/issue-13466.rs:14:9 | +LL | let _x: usize = match Some(1) { + | ------- this match expression has type `std::option::Option<{integer}>` +... LL | Err(e) => panic!(e) | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr index cd629841fee83..de9757d5d32ed 100644 --- a/src/test/ui/issues/issue-15896.stderr +++ b/src/test/ui/issues/issue-15896.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/issue-15896.rs:11:11 | +LL | let u = match e { + | - this match expression has type `main::R` +LL | E::B( LL | Tau{t: x}, | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` | diff --git a/src/test/ui/issues/issue-16401.stderr b/src/test/ui/issues/issue-16401.stderr index a1cf6c98705aa..1779d0befd871 100644 --- a/src/test/ui/issues/issue-16401.stderr +++ b/src/test/ui/issues/issue-16401.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-16401.rs:8:9 | +LL | match () { + | -- this match expression has type `()` LL | Slice { data: data, len: len } => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `Slice` | diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr index 78c3f92fb53b5..51903cfadab15 100644 --- a/src/test/ui/issues/issue-3680.stderr +++ b/src/test/ui/issues/issue-3680.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-3680.rs:3:9 | +LL | match None { + | ---- this match expression has type `std::option::Option<_>` LL | Err(_) => () | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index a6f6229fe78d2..0a918a789703e 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -28,6 +28,8 @@ LL | (true, false, false) => () error[E0308]: mismatched types --> $DIR/issue-5100.rs:33:9 | +LL | match (true, false) { + | ------------- this match expression has type `(bool, bool)` LL | box (true, false) => () | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box` | diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr index dbbafb38e6580..649a0c1581a68 100644 --- a/src/test/ui/issues/issue-5358-1.stderr +++ b/src/test/ui/issues/issue-5358-1.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-5358-1.rs:6:9 | +LL | match S(Either::Left(5)) { + | ------------------ this match expression has type `S` LL | Either::Right(_) => {} | ^^^^^^^^^^^^^^^^ expected struct `S`, found enum `Either` | diff --git a/src/test/ui/issues/issue-57472.rs b/src/test/ui/issues/issue-57472.rs new file mode 100644 index 0000000000000..1131006374c64 --- /dev/null +++ b/src/test/ui/issues/issue-57472.rs @@ -0,0 +1,35 @@ +#![crate_type="lib"] +#![deny(unreachable_patterns)] + +mod test_struct { + // Test the exact copy of the minimal example + // posted in the issue. + pub struct Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_], .. } => println!("foo"), + Punned { bar: [_], .. } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} + +mod test_union { + // Test the same thing using a union. + pub union Punned { + foo: [u8; 1], + bar: [u8; 1], + } + + pub fn test(punned: Punned) { + match punned { + Punned { foo: [_] } => println!("foo"), + Punned { bar: [_] } => println!("bar"), + //~^ ERROR unreachable pattern [unreachable_patterns] + } + } +} diff --git a/src/test/ui/issues/issue-57472.stderr b/src/test/ui/issues/issue-57472.stderr new file mode 100644 index 0000000000000..b6dd7e2494186 --- /dev/null +++ b/src/test/ui/issues/issue-57472.stderr @@ -0,0 +1,20 @@ +error: unreachable pattern + --> $DIR/issue-57472.rs:15:13 + | +LL | Punned { bar: [_], .. } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-57472.rs:2:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/issue-57472.rs:31:13 + | +LL | Punned { bar: [_] } => println!("bar"), + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-7092.stderr b/src/test/ui/issues/issue-7092.stderr index aa24182e3a39d..7bb6820287487 100644 --- a/src/test/ui/issues/issue-7092.stderr +++ b/src/test/ui/issues/issue-7092.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/issue-7092.rs:6:9 | +LL | match x { + | - this match expression has type `Whatever` LL | Some(field) => | ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option` | diff --git a/src/test/ui/match/match-struct.stderr b/src/test/ui/match/match-struct.stderr index bad41485a53b1..2a24a293e9836 100644 --- a/src/test/ui/match/match-struct.stderr +++ b/src/test/ui/match/match-struct.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/match-struct.rs:6:9 | +LL | match (S { a: 1 }) { + | ------------ this match expression has type `S` LL | E::C(_) => (), | ^^^^^^^ expected struct `S`, found enum `E` | diff --git a/src/test/ui/match/match-tag-unary.stderr b/src/test/ui/match/match-tag-unary.stderr index c90029b2fa12e..53b6635136966 100644 --- a/src/test/ui/match/match-tag-unary.stderr +++ b/src/test/ui/match/match-tag-unary.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/match-tag-unary.rs:4:43 | LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } //~ ERROR mismatched types - | ^^^^^^^ expected enum `A`, found enum `B` + | - ^^^^^^^ expected enum `A`, found enum `B` + | | + | this match expression has type `A` | = note: expected type `A` found type `B` diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index c17d4b70f0b00..c2810d764c2ce 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -21,6 +21,8 @@ LL | A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but error[E0308]: mismatched types --> $DIR/pattern-error-continue.rs:22:9 | +LL | match 'c' { + | --- this match expression has type `char` LL | S { .. } => (), | ^^^^^^^^ expected char, found struct `S` | diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index dae17fa516610..69cd552aabd1b 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/pattern-tyvar.rs:5:18 | +LL | match t { + | - this match expression has type `std::option::Option>` LL | Bar::T1(_, Some::(x)) => { //~ ERROR mismatched types | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found isize | diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr index 3c1ed8e69a6bd..cc62316bec185 100644 --- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -109,6 +109,8 @@ LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:54:9 | +LL | match (Point { x: 1, y: 2 }) { + | ---------------------- this match expression has type `Point<{integer}>` LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments | ^^^^^^^^^^^^^^^^^^^^ expected integer, found f32 | @@ -118,6 +120,8 @@ LL | PointF:: { .. } => {} //~ ERROR wrong number of type arguments error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:59:9 | +LL | match (Point { x: 1, y: 2 }) { + | ---------------------- this match expression has type `Point<{integer}>` LL | PointF { .. } => {} //~ ERROR mismatched types | ^^^^^^^^^^^^^ expected integer, found f32 | @@ -127,6 +131,8 @@ LL | PointF { .. } => {} //~ ERROR mismatched types error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:67:9 | +LL | match (Pair { x: 1, y: 2 }) { + | --------------------- this match expression has type `Pair<{integer}, {integer}>` LL | PairF:: { .. } => {} //~ ERROR mismatched types | ^^^^^^^^^^^^^^^^^^^ expected integer, found f32 |