From e5761822c7b1621dc67173e4babcf3999b8012b4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 7 Sep 2018 17:45:01 +0300 Subject: [PATCH 1/2] rustc: support turning trait errors into lints via ObligationCauseCode. --- .../infer/error_reporting/need_type_info.rs | 168 +++++++++--------- src/librustc/infer/mod.rs | 4 +- src/librustc/infer/outlives/env.rs | 10 +- src/librustc/mir/interpret/error.rs | 18 +- src/librustc/traits/error_reporting.rs | 107 ++++++++--- src/librustc/traits/fulfill.rs | 4 +- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/query/outlives_bounds.rs | 52 ++++-- src/librustc/traits/select.rs | 4 +- src/librustc/ty/context.rs | 6 +- src/librustc/ty/util.rs | 2 +- src/librustc/ty/wf.rs | 36 ++-- src/librustc_mir/transform/qualify_consts.rs | 2 +- .../implied_outlives_bounds.rs | 6 +- src/librustc_typeck/check/closure.rs | 5 +- src/librustc_typeck/check/compare_method.rs | 26 +-- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/mod.rs | 36 ++-- src/librustc_typeck/check/regionck.rs | 9 +- src/librustc_typeck/check/wfcheck.rs | 72 ++++---- src/librustc_typeck/check/writeback.rs | 10 +- src/librustc_typeck/coherence/builtin.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/test/ui/issues/issue-23046.rs | 4 +- src/test/ui/issues/issue-23046.stderr | 6 +- 25 files changed, 347 insertions(+), 248 deletions(-) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 505b1bc032d20..757068783b0e8 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -8,71 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::{self, Local, Pat, Body, HirId}; -use hir::intravisit::{self, Visitor, NestedVisitorMap}; +use hir::{self, HirId}; use infer::InferCtxt; use infer::type_variable::TypeVariableOrigin; +use traits; use ty::{self, Ty, Infer, TyVar}; use syntax::source_map::CompilerDesugaringKind; -use syntax_pos::Span; use errors::DiagnosticBuilder; -struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - target_ty: &'a Ty<'tcx>, - hir_map: &'a hir::map::Map<'gcx>, - found_local_pattern: Option<&'gcx Pat>, - found_arg_pattern: Option<&'gcx Pat>, -} - -impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn node_matches_type(&mut self, node_id: HirId) -> bool { - let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { - tables.borrow().node_id_to_type_opt(node_id) - }); - match ty_opt { - Some(ty) => { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - ty.walk().any(|inner_ty| { - inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { - (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { - self.infcx - .type_variables - .borrow_mut() - .sub_unified(a_vid, b_vid) - } - _ => false, - } - }) - } - None => false, - } - } -} - -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { - NestedVisitorMap::OnlyBodies(&self.hir_map) - } - - fn visit_local(&mut self, local: &'gcx Local) { - if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) { - self.found_local_pattern = Some(&*local.pat); - } - intravisit::walk_local(self, local); - } - - fn visit_body(&mut self, body: &'gcx Body) { - for argument in &body.arguments { - if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) { - self.found_arg_pattern = Some(&*argument.pat); - } - } - intravisit::walk_body(self, body); - } -} - - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { if let ty::Infer(ty::TyVar(ty_vid)) = (*ty).sty { @@ -89,38 +32,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn need_type_info_err(&self, - body_id: Option, - span: Span, - ty: Ty<'tcx>) - -> DiagnosticBuilder<'gcx> { + cause: &traits::ObligationCause<'tcx>, + ty: Ty<'tcx>) + -> DiagnosticBuilder<'gcx> { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); - let mut err_span = span; let mut labels = vec![( - span, + cause.span, if &name == "_" { "cannot infer type".to_string() } else { format!("cannot infer type for `{}`", name) }, )]; + let mut span = cause.span; - let mut local_visitor = FindLocalByTypeVisitor { - infcx: &self, - target_ty: &ty, - hir_map: &self.tcx.hir, - found_local_pattern: None, - found_arg_pattern: None, - }; - - if let Some(body_id) = body_id { - let expr = self.tcx.hir.expect_expr(body_id.node_id); - local_visitor.visit_expr(expr); + // NB. Lower values are more preferred. + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum LocalKind { + ClosureArg, + Let, } - if let Some(pattern) = local_visitor.found_arg_pattern { - err_span = pattern.span; + let found_local = self.in_progress_tables.and_then(|tables| { + let tables = tables.borrow(); + let local_id_root = tables.local_id_root?; + assert!(local_id_root.is_local()); + + tables.node_types().iter().filter_map(|(&local_id, &node_ty)| { + let node_id = self.tcx.hir.hir_to_node_id(HirId { + owner: local_id_root.index, + local_id, + }); + + let (kind, pattern) = match self.tcx.hir.find(node_id) { + Some(hir::Node::Local(local)) => { + (LocalKind::Let, &*local.pat) + } + + Some(hir::Node::Binding(pat)) | + Some(hir::Node::Pat(pat)) => { + let parent_id = self.tcx.hir.get_parent_node(node_id); + match self.tcx.hir.find(parent_id) { + Some(hir::Node::Expr(e)) => { + match e.node { + hir::ExprKind::Closure(..) => {} + _ => return None, + } + } + _ => return None, + } + + (LocalKind::ClosureArg, pat) + } + + _ => return None + }; + + let node_ty = self.resolve_type_vars_if_possible(&node_ty); + let matches_type = node_ty.walk().any(|inner_ty| { + inner_ty == ty || match (&inner_ty.sty, &ty.sty) { + (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { + self.type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid) + } + _ => false, + } + }); + if !matches_type { + return None; + } + + Some((kind, pattern)) + }).min_by_key(|&(kind, pattern)| (kind, pattern.hir_id.local_id)) + }); + + if let Some((LocalKind::ClosureArg, pattern)) = found_local { + span = pattern.span; // We don't want to show the default label for closures. // // So, before clearing, the output would look something like this: @@ -139,7 +129,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { labels.clear(); labels.push( (pattern.span, "consider giving this closure parameter a type".to_string())); - } else if let Some(pattern) = local_visitor.found_local_pattern { + } else if let Some((LocalKind::Let, pattern)) = found_local { if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.compiler_desugaring_kind() { None => labels.push((pattern.span, @@ -155,10 +145,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - let mut err = struct_span_err!(self.tcx.sess, - err_span, - E0282, - "type annotations needed"); + let lint = self.get_lint_from_cause_code(&cause.code); + macro_rules! struct_span_err_or_lint { + ($code:ident, $($message:tt)*) => { + match lint { + Some((lint, id)) => { + let message = format!($($message)*); + self.tcx.struct_span_lint_node(lint, id, span, &message) + } + None => { + struct_span_err!(self.tcx.sess, span, $code, $($message)*) + } + } + } + } + + let mut err = struct_span_err_or_lint!(E0282, "type annotations needed"); for (target_span, label_message) in labels { err.span_label(target_span, label_message); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e628a3458f9e6..160048b37df68 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1424,8 +1424,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// new obligations that must further be processed. pub fn partially_normalize_associated_types_in( &self, - span: Span, - body_id: ast::NodeId, + cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: &T, ) -> InferOk<'tcx, T> @@ -1434,7 +1433,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("partially_normalize_associated_types_in(value={:?})", value); let mut selcx = traits::SelectionContext::new(self); - let cause = ObligationCause::misc(span, body_id); let traits::Normalized { value, obligations } = traits::normalize(&mut selcx, param_env, cause, value); debug!( diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs index 7f59a6794efbd..f9d3518d550c8 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc/infer/outlives/env.rs @@ -10,12 +10,9 @@ use infer::{GenericKind, InferCtxt}; use infer::outlives::free_region_map::FreeRegionMap; -use traits::query::outlives_bounds::{self, OutlivesBound}; +use traits::{self, query::outlives_bounds::{self, OutlivesBound}}; use ty::{self, Ty}; -use syntax::ast; -use syntax_pos::Span; - /// The `OutlivesEnvironment` collects information about what outlives /// what in a given type-checking setting. For example, if we have a /// where-clause like `where T: 'a` in scope, then the @@ -136,15 +133,14 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> { &mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, fn_sig_tys: &[Ty<'tcx>], - body_id: ast::NodeId, - span: Span, + cause: &traits::ObligationCause<'tcx>, ) { debug!("add_implied_bounds()"); for &ty in fn_sig_tys { let ty = infcx.resolve_type_vars_if_possible(&ty); debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, cause, ty); self.add_outlives_bounds(Some(infcx), implied_bounds) } } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index cccde692bf789..13ea8bd532a4a 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -55,6 +55,16 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_generic(tcx, message, None) } + pub fn struct_lint(&self, + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + message: &str, + lint_root: ast::NodeId, + lint: Option<&'static ::lint::Lint>) + -> Option> + { + self.struct_generic(tcx, message, Some((lint_root, lint))) + } + pub fn report_as_error(&self, tcx: TyCtxtAt<'a, 'gcx, 'tcx>, message: &str @@ -73,7 +83,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { let lint = self.struct_generic( tcx, message, - Some(lint_root), + Some((lint_root, None)), ); if let Some(mut lint) = lint { lint.emit(); @@ -84,7 +94,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { &self, tcx: TyCtxtAt<'a, 'gcx, 'tcx>, message: &str, - lint_root: Option, + lint_root: Option<(ast::NodeId, Option<&'static ::lint::Lint>)>, ) -> Option> { match self.error.kind { ::mir::interpret::EvalErrorKind::TypeckError | @@ -97,7 +107,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { _ => {}, } trace!("reporting const eval failure at {:?}", self.span); - let mut err = if let Some(lint_root) = lint_root { + let mut err = if let Some((lint_root, lint)) = lint_root { let node_id = self.stacktrace .iter() .rev() @@ -105,7 +115,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { .next() .unwrap_or(lint_root); tcx.struct_span_lint_node( - ::rustc::lint::builtin::CONST_ERR, + lint.unwrap_or(::rustc::lint::builtin::CONST_ERR), node_id, tcx.span, message, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 466d472cca338..8602e7563b8bd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -50,7 +50,6 @@ use syntax_pos::{DUMMY_SP, Span}; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>], - body_id: Option, fallback_has_occurred: bool) { #[derive(Debug)] struct ErrorDescriptor<'tcx> { @@ -111,7 +110,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for (error, suppressed) in errors.iter().zip(is_suppressed) { if !suppressed { - self.report_fulfillment_error(error, body_id, fallback_has_occurred); + self.report_fulfillment_error(error, fallback_has_occurred); } } } @@ -155,7 +154,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>, - body_id: Option, fallback_has_occurred: bool) { debug!("report_fulfillment_errors({:?})", error); match error.code { @@ -166,7 +164,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_projection_error(&error.obligation, e); } FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation, body_id); + self.maybe_report_ambiguity(&error.obligation); } FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { self.report_mismatched_types(&error.obligation.cause, @@ -224,13 +222,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + + let span = obligation.cause.span; + let lint = self.get_lint_from_cause_code(&obligation.cause.code); + macro_rules! struct_span_err_or_lint { + ($code:ident, $($message:tt)*) => { + match lint { + Some((lint, id)) => { + let message = format!($($message)*); + self.tcx.struct_span_lint_node(lint, id, span, &message) + } + None => { + struct_span_err!(self.tcx.sess, span, $code, $($message)*) + } + } + } + } + let msg = format!("type mismatch resolving `{}`", predicate); let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg.clone()); let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); if fresh { - let mut diag = struct_span_err!( - self.tcx.sess, obligation.cause.span, E0271, + let mut diag = struct_span_err_or_lint!( + E0271, "type mismatch resolving `{}`", predicate ); self.note_type_err(&mut diag, &obligation.cause, None, values, err); @@ -559,6 +574,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Get the lint and `NodeId` it applies to, if any exist. + pub fn get_lint_from_cause_code( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(&'static ::lint::Lint, ast::NodeId)> { + match code { + ObligationCauseCode::BuiltinDerivedObligation(data) | + ObligationCauseCode::ImplDerivedObligation(data) => { + self.get_lint_from_cause_code(&data.parent_code) + } + _ => None, + } + } + pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, @@ -566,6 +595,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let span = obligation.cause.span; + let lint = self.get_lint_from_cause_code(&obligation.cause.code); + macro_rules! struct_span_err_or_lint { + ($code:ident, $($message:tt)*) => { + match lint { + Some((lint, id)) => { + let message = format!($($message)*); + self.tcx.struct_span_lint_node(lint, id, span, &message) + } + None => { + struct_span_err!(self.tcx.sess, span, $code, $($message)*) + } + } + } + } + let mut err = match *error { SelectionError::Unimplemented => { if let ObligationCauseCode::CompareImplMethodObligation { @@ -580,6 +624,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .emit(); return; } + match obligation.predicate { ty::Predicate::Trait(ref trait_predicate) => { let trait_predicate = @@ -598,9 +643,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); - let mut err = struct_span_err!( - self.tcx.sess, - span, + let mut err = struct_span_err_or_lint!( E0277, "{}", message.unwrap_or_else(|| { @@ -694,7 +737,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.region_outlives_predicate(&obligation.cause, &predicate).err().unwrap(); - struct_span_err!(self.tcx.sess, span, E0279, + struct_span_err_or_lint!(E0279, "the requirement `{}` is not satisfied (`{}`)", predicate, err) } @@ -702,7 +745,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); - struct_span_err!(self.tcx.sess, span, E0280, + struct_span_err_or_lint!(E0280, "the requirement `{}` is not satisfied", predicate) } @@ -841,10 +884,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ConstEvalFailure(ref err) => { - match err.struct_error( - self.tcx.at(span), - "could not evaluate constant expression", - ) { + let err = if let Some((lint, id)) = lint { + err.struct_lint( + self.tcx.at(span), + "could not evaluate constant expression", + id, + Some(lint), + ) + } else { + err.struct_error( + self.tcx.at(span), + "could not evaluate constant expression", + ) + }; + match err { Some(err) => err, None => return, } @@ -1230,8 +1283,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>, - body_id: Option) { + fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a @@ -1250,6 +1302,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } + // Avoid erroring about inference variables in lint mode. + if let Some((lint, id)) = self.get_lint_from_cause_code(&obligation.cause.code) { + match self.tcx.lint_level_at_node(lint, id).0 { + // These are the only cases in which we can't detect whether + // a diagnostic was emitted (as it likely wasn't an error). + ::lint::Level::Allow | + ::lint::Level::Warn => return, + + ::lint::Level::Deny | + ::lint::Level::Forbid => {} + } + } + match predicate { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); @@ -1286,7 +1351,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items().sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info_err(body_id, span, self_ty).emit(); + self.need_type_info_err(&obligation.cause, self_ty).emit(); } else { let mut err = struct_span_err!(self.tcx.sess, span, E0283, @@ -1303,7 +1368,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info_err(body_id, span, ty).emit(); + self.need_type_info_err(&obligation.cause, ty).emit(); } } @@ -1314,9 +1379,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, - obligation.cause.span, - a).emit(); + self.need_type_info_err(&obligation.cause, a).emit(); } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9998db4ad1d48..9ee52ecbdf00b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -440,8 +440,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.selcx.infcx(), obligation.param_env, - obligation.cause.body_id, - ty, obligation.cause.span) { + &obligation.cause, + ty) { None => { pending_obligation.stalled_on = vec![ty]; ProcessResult::Unchanged diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e2dbe88354060..485d8041c5ee1 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -700,7 +700,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ) { Ok(predicates) => predicates, Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.report_fulfillment_errors(&errors, false); // An unnormalized env is better than nothing. return elaborated_env; } diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 47c8ee357fbe8..c2fc0c829cfc8 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -9,8 +9,6 @@ // except according to those terms. use infer::InferCtxt; -use syntax::ast; -use syntax::source_map::Span; use smallvec::SmallVec; use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; use traits::query::NoSolution; @@ -99,36 +97,54 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, + cause: &ObligationCause<'tcx>, ty: Ty<'tcx>, - span: Span, ) -> Vec> { debug!("implied_outlives_bounds(ty = {:?})", ty); + let mut skip_delay_bug = false; + + // Avoid ICE-ing from unsolved inference variables in lint mode. + if let Some((lint, id)) = self.get_lint_from_cause_code(&cause.code) { + match self.tcx.lint_level_at_node(lint, id).0 { + // These are the only cases in which we can't detect whether + // a diagnostic was emitted (as it likely wasn't an error). + ::lint::Level::Allow | + ::lint::Level::Warn => skip_delay_bug = true, + + ::lint::Level::Deny | + ::lint::Level::Forbid => {} + } + } + let mut orig_values = SmallVec::new(); let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); let result = match self.tcx.global_tcx().implied_outlives_bounds(key) { Ok(r) => r, Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations" - ); + if !skip_delay_bug { + self.tcx.sess.delay_span_bug( + cause.span, + "implied_outlives_bounds failed to solve all obligations" + ); + } return vec![]; } }; assert!(result.value.is_proven()); let result = self.instantiate_query_result_and_region_obligations( - &ObligationCause::misc(span, body_id), param_env, &orig_values, &result); + cause, param_env, &orig_values, &result); debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); let result = match result { Ok(v) => v, Err(_) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to instantiate" - ); + if !skip_delay_bug { + self.tcx.sess.delay_span_bug( + cause.span, + "implied_outlives_bounds failed to instantiate" + ); + } return vec![]; } }; @@ -138,10 +154,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { let mut fulfill_cx = FulfillmentContext::new(); fulfill_cx.register_predicate_obligations(self, result.obligations); if fulfill_cx.select_all_or_error(self).is_err() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation" - ); + if !skip_delay_bug { + self.tcx.sess.delay_span_bug( + cause.span, + "implied_outlives_bounds failed to solve obligations from instantiation" + ); + } } result.value diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 232ef108537fe..4727aa3775078 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -682,8 +682,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.param_env, - obligation.cause.body_id, - ty, obligation.cause.span) { + &obligation.cause, + ty) { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), None => diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6738267b5b8c8..d9a47ea5e407e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2824,7 +2824,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir_id: HirId, span: S, msg: &str) - -> DiagnosticBuilder<'tcx> + -> DiagnosticBuilder<'gcx> { let node_id = self.hir.hir_to_node_id(hir_id); let (level, src) = self.lint_level_at_node(lint, node_id); @@ -2836,14 +2836,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { id: NodeId, span: S, msg: &str) - -> DiagnosticBuilder<'tcx> + -> DiagnosticBuilder<'gcx> { let (level, src) = self.lint_level_at_node(lint, id); lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg) } pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str) - -> DiagnosticBuilder<'tcx> + -> DiagnosticBuilder<'gcx> { let (level, src) = self.lint_level_at_node(lint, id); lint::struct_lint_level(self.sess, lint, level, src, None, msg) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index cc0429de2f624..9cd87d07b09a8 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -217,7 +217,7 @@ impl<'tcx> ty::ParamEnv<'tcx> { infringing.push(field); } Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.report_fulfillment_errors(&errors, false); } }; } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 63206a660df41..c2bad44db4266 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -15,8 +15,6 @@ use ty::subst::Substs; use traits; use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; -use syntax::ast; -use syntax_pos::Span; use middle::lang_items; /// Returns the set of obligations needed to make `ty` well-formed. @@ -27,20 +25,15 @@ use middle::lang_items; /// say "$0 is WF if $0 is WF". pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span) + parent_cause: &traits::ObligationCause<'tcx>, + ty: Ty<'tcx>) -> Option>> { - let mut wf = WfPredicates { infcx, - param_env, - body_id, - span, - out: vec![] }; + let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] }; if wf.compute(ty) { - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); + debug!("wf::obligations({:?}, parent_cause={:?}) = {:?}", ty, parent_cause, wf.out); let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); + debug!("wf::obligations({:?}, parent_cause={:?}) ~~> {:?}", ty, parent_cause, result); Some(result) } else { None // no progress made, return None @@ -53,24 +46,22 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// if `Bar: Eq`. pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - trait_ref: &ty::TraitRef<'tcx>, - span: Span) + parent_cause: &traits::ObligationCause<'tcx>, + trait_ref: &ty::TraitRef<'tcx>) -> Vec> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; + let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] }; wf.compute_trait_ref(trait_ref, Elaborate::All); wf.normalize() } pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - predicate: &ty::Predicate<'tcx>, - span: Span) + parent_cause: &traits::ObligationCause<'tcx>, + predicate: &ty::Predicate<'tcx>) -> Vec> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; + let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] }; // (*) ok to skip binders, because wf code is prepared for it match *predicate { @@ -114,8 +105,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - span: Span, + parent_cause: &'a traits::ObligationCause<'tcx>, out: Vec>, } @@ -150,7 +140,7 @@ enum Elaborate { impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { - traits::ObligationCause::new(self.span, self.body_id, code) + traits::ObligationCause::new(self.parent_cause.span, self.parent_cause.body_id, code) } fn normalize(&mut self) -> Vec> { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a2175dce33a83..c7418a2e1ca8c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1258,7 +1258,7 @@ impl MirPass for QualifyAndPromoteConstants { tcx.require_lang_item(lang_items::SyncTraitLangItem), cause); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err, None, false); + infcx.report_fulfillment_errors(&err, false); } }); } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 7b31518c07b18..dc35965974570 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -22,7 +22,7 @@ use rustc::ty::query::Providers; use rustc::ty::wf; use syntax::ast::DUMMY_NODE_ID; use syntax::source_map::DUMMY_SP; -use rustc::traits::FulfillmentContext; +use rustc::traits::{self, FulfillmentContext}; use rustc_data_structures::sync::Lrc; @@ -73,8 +73,8 @@ fn compute_implied_outlives_bounds<'tcx>( // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) - let obligations = - wf::obligations(infcx, param_env, DUMMY_NODE_ID, ty, DUMMY_SP).unwrap_or(vec![]); + let cause = traits::ObligationCause::new(DUMMY_SP, DUMMY_NODE_ID, traits::MiscObligation); + let obligations = wf::obligations(infcx, param_env, &cause, ty).unwrap_or(vec![]); // NB: All of these predicates *ought* to be easily proven // true. In fact, their correctness is (mostly) implied by diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index a283e032e0e02..b6a5350275be2 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::{InferOk, InferResult}; use rustc::infer::LateBoundRegionConversionTime; use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::traits::error_reporting::ArgKind; +use rustc::traits::{self, error_reporting::ArgKind}; use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; @@ -667,8 +667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let liberated_sig = self.tcx() .liberate_late_bound_regions(expr_def_id, &bound_sig); let liberated_sig = self.inh.normalize_associated_types_in( - body.value.span, - body.value.id, + traits::ObligationCause::misc(body.value.span, body.value.id), self.param_env, &liberated_sig, ); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 9aa2ba363ed7a..0596e45d987fe 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -266,8 +266,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, infer::HigherRankedType, &tcx.fn_sig(impl_m.def_id)); let impl_sig = - inh.normalize_associated_types_in(impl_m_span, - impl_m_node_id, + inh.normalize_associated_types_in(ObligationCause::misc(impl_m_span, + impl_m_node_id), param_env, &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig)); @@ -279,8 +279,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = - inh.normalize_associated_types_in(impl_m_span, - impl_m_node_id, + inh.normalize_associated_types_in(ObligationCause::misc(impl_m_span, + impl_m_node_id), param_env, &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); @@ -345,14 +345,15 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + infcx.report_fulfillment_errors(errors, false); return Err(ErrorReported); } // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id); - fcx.regionck_item(impl_m_node_id, impl_m_span, &[]); + fcx.regionck_item(impl_m_node_id, impl_m_span, + ObligationCauseCode::MiscObligation, &[]); Ok(()) }) @@ -924,15 +925,15 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); // There is no "body" here, so just pass dummy id. - let impl_ty = inh.normalize_associated_types_in(impl_c_span, - impl_c_node_id, + let impl_ty = inh.normalize_associated_types_in(ObligationCause::misc(impl_c_span, + impl_c_node_id), param_env, &impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = inh.normalize_associated_types_in(impl_c_span, - impl_c_node_id, + let trait_ty = inh.normalize_associated_types_in(ObligationCause::misc(impl_c_span, + impl_c_node_id), param_env, &trait_ty); @@ -983,11 +984,12 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(errors, None, false); + infcx.report_fulfillment_errors(errors, false); return; } let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id); - fcx.regionck_item(impl_c_node_id, impl_c_span, &[]); + fcx.regionck_item(impl_c_node_id, impl_c_span, + ObligationCauseCode::MiscObligation, &[]); }); } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 9d3cbf910e059..6749f509972b7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -112,7 +112,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { // this could be reached when we get lazy normalization - infcx.report_fulfillment_errors(errors, None, false); + infcx.report_fulfillment_errors(errors, false); return Err(ErrorReported); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aa27fe528e1fd..9517a5940160a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -225,8 +225,6 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// environment is for an item or something where the "callee" is /// not clear. implicit_region_bound: Option>, - - body_id: Option, } impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { @@ -637,7 +635,6 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { deferred_generator_interiors: RefCell::new(Vec::new()), opaque_types: RefCell::new(DefIdMap()), implicit_region_bound, - body_id, } } @@ -665,13 +662,12 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } fn normalize_associated_types_in(&self, - span: Span, - body_id: ast::NodeId, + cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { - let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); + let ok = self.partially_normalize_associated_types_in(cause, param_env, value); self.register_infer_ok_obligations(ok) } } @@ -847,8 +843,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); let fn_sig = - inh.normalize_associated_types_in(body.value.span, - body_id.node_id, + inh.normalize_associated_types_in(ObligationCause::misc(body.value.span, + body_id.node_id), param_env, &fn_sig); @@ -2259,17 +2255,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) + self.inh.normalize_associated_types_in( + ObligationCause::misc(span, self.body_id), + self.param_env, + value, + ) } fn normalize_associated_types_in_as_infer_ok(&self, span: Span, value: &T) -> InferOk<'tcx, T> where T : TypeFoldable<'tcx> { - self.inh.partially_normalize_associated_types_in(span, - self.body_id, - self.param_env, - value) + self.inh.partially_normalize_associated_types_in( + ObligationCause::misc(span, self.body_id), + self.param_env, + value, + ) } pub fn require_type_meets(&self, @@ -2430,7 +2431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { - self.report_fulfillment_errors(&errors, self.inh.body_id, false); + self.report_fulfillment_errors(&errors, false); } } @@ -2439,7 +2440,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.fulfillment_cx.borrow_mut().select_where_possible(self) { Ok(()) => { } Err(errors) => { - self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + self.report_fulfillment_errors(&errors, fallback_has_occurred); }, } } @@ -5244,7 +5245,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty) + self.need_type_info_err( + &ObligationCause::misc(sp, self.body_id), + ty, + ) .note("type must be known at this point") .emit(); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 05fe0cb9262cc..01adc8c009fa7 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -88,6 +88,7 @@ use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use middle::region; use rustc::hir::def_id::DefId; +use rustc::traits; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; use rustc::infer; @@ -139,6 +140,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn regionck_item(&self, item_id: ast::NodeId, span: Span, + code: traits::ObligationCauseCode<'tcx>, wf_tys: &[Ty<'tcx>]) { debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys); let subject = self.tcx.hir.local_def_id(item_id); @@ -147,7 +149,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_id, Subject(subject), self.param_env); - rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); + let cause = traits::ObligationCause::new(span, item_id, code); + rcx.outlives_environment.add_implied_bounds(self, wf_tys, &cause); rcx.visit_region_obligations(item_id); rcx.resolve_regions_and_report_errors(); } @@ -331,8 +334,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.outlives_environment.add_implied_bounds( self.fcx, &fn_sig_tys[..], - body_id.node_id, - span); + &traits::ObligationCause::misc(span, body_id.node_id), + ); self.link_fn_args(region::Scope::Node(body.value.hir_id.local_id), &body.arguments); self.visit_body(body); self.visit_region_obligations(body_id.node_id); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9e09f2cd1851e..33cecb26a4453 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -36,9 +36,15 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { id: ast::NodeId, span: Span, param_env: ty::ParamEnv<'tcx>, + cause_code: ObligationCauseCode<'tcx>, } impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { + fn with_cause_code(&mut self, cause_code: ObligationCauseCode<'tcx>) -> &mut Self { + self.cause_code = cause_code; + self + } + fn with_fcx(&'tcx mut self, f: F) where F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>, TyCtxt<'b, 'gcx, 'gcx>) -> Vec> @@ -46,6 +52,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; let param_env = self.param_env; + let cause_code = self.cause_code.clone(); self.inherited.enter(|inh| { let fcx = FnCtxt::new(&inh, param_env, id); if !inh.tcx.features().trivial_bounds { @@ -56,7 +63,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { } let wf_tys = f(&fcx, fcx.tcx.global_tcx()); fcx.select_all_obligations_or_error(); - fcx.regionck_item(id, span, &wf_tys); + fcx.regionck_item(id, span, cause_code, &wf_tys); }); } } @@ -118,11 +125,16 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def hir::ItemKind::Fn(..) => { check_item_fn(tcx, item); } - hir::ItemKind::Static(..) => { - check_item_type(tcx, item); - } + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { - check_item_type(tcx, item); + for_item(tcx, item).with_fcx(|fcx, _this| { + let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); + let item_ty = fcx.normalize_associated_types_in(item.span, &ty); + + fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation); + + vec![] // no implied bounds in a static/const + }); } hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { check_type_defn(tcx, item, false, |fcx| { @@ -232,6 +244,7 @@ fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId, span: Sp id, span, param_env: tcx.param_env(def_id), + cause_code: ObligationCauseCode::MiscObligation, } } @@ -296,7 +309,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - check_where_clauses(tcx, fcx, item.span, def_id, None); + check_where_clauses(tcx, fcx, item.span, def_id, None, + traits::ItemObligation(def_id)); vec![] // no implied bounds in a struct def'n }); @@ -305,7 +319,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { let trait_def_id = tcx.hir.local_def_id(item.id); for_item(tcx, item).with_fcx(|fcx, _| { - check_where_clauses(tcx, fcx, item.span, trait_def_id, None); + check_where_clauses(tcx, fcx, item.span, trait_def_id, None, + traits::ItemObligation(trait_def_id)); vec![] }); } @@ -322,21 +337,6 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { }) } -fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::Item) -{ - debug!("check_item_type: {:?}", item); - - for_item(tcx, item).with_fcx(|fcx, _this| { - let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); - let item_ty = fcx.normalize_associated_types_in(item.span, &ty); - - fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation); - - vec![] // no implied bounds in a const etc - }); -} - fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item, ast_self_ty: &hir::Ty, @@ -353,12 +353,16 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_ref = fcx.normalize_associated_types_in( ast_trait_ref.path.span, &trait_ref); + let cause = traits::ObligationCause::new( + ast_trait_ref.path.span, + fcx.body_id, + ObligationCauseCode::MiscObligation, + ); let obligations = ty::wf::trait_obligations(fcx, fcx.param_env, - fcx.body_id, - &trait_ref, - ast_trait_ref.path.span); + &cause, + &trait_ref); for obligation in obligations { fcx.register_predicate(obligation); } @@ -371,7 +375,8 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - check_where_clauses(tcx, fcx, item.span, item_def_id, None); + check_where_clauses(tcx, fcx, item.span, item_def_id, None, + traits::ItemObligation(item_def_id)); fcx.impl_implied_bounds(item_def_id, item.span) }); @@ -384,6 +389,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( span: Span, def_id: DefId, return_ty: Option>, + code: traits::ObligationCauseCode<'tcx>, ) { use ty::subst::Subst; use rustc::ty::TypeFoldable; @@ -448,6 +454,9 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( } } }); + + let cause = traits::ObligationCause::new(span, fcx.body_id, code); + // Now we build the substituted predicates. let default_obligations = predicates.predicates.iter().flat_map(|&pred| { struct CountParams { params: FxHashSet } @@ -493,8 +502,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // below: there, we are not trying to prove those predicates // to be *true* but merely *well-formed*. let pred = fcx.normalize_associated_types_in(span, &pred); - let cause = traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def_id)); - traits::Obligation::new(cause, fcx.param_env, pred) + traits::Obligation::new(cause.clone(), fcx.param_env, pred) }); let mut predicates = predicates.instantiate_identity(fcx.tcx); @@ -511,9 +519,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( .iter() .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, - fcx.body_id, - p, - span)); + &cause, + p)); for obligation in wf_obligations.chain(default_obligations) { debug!("next obligation cause: {:?}", obligation.cause); @@ -541,7 +548,8 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); - check_where_clauses(tcx, fcx, span, def_id, Some(sig.output())); + check_where_clauses(tcx, fcx, span, def_id, Some(sig.output()), + traits::ItemObligation(def_id)); } /// Checks "defining uses" of existential types to ensure that they meet the restrictions laid for diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0b2f92ac4bcb6..7881152c35e68 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -17,6 +17,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::InferCtxt; +use rustc::traits; use rustc::ty::adjustment::{Adjust, Adjustment}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use rustc::ty::subst::UnpackedKind; @@ -738,8 +739,13 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { fn report_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { - self.infcx - .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t) + self.infcx.need_type_info_err( + &traits::ObligationCause::misc( + self.span.to_span(&self.tcx), + self.body.id().node_id, + ), + t, + ) .emit(); } } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index efc35fad820c8..722ace8cb9f6a 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, // Check that all transitive obligations are satisfied. if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.report_fulfillment_errors(&errors, false); } // Finally, resolve all regions. diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index c9aa0339dd469..213493e98dd58 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -172,7 +172,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match fulfill_cx.select_all_or_error(infcx) { Ok(()) => true, Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.report_fulfillment_errors(&errors, false); false } } diff --git a/src/test/ui/issues/issue-23046.rs b/src/test/ui/issues/issue-23046.rs index 670706b7a9adf..ce2758ba2abcd 100644 --- a/src/test/ui/issues/issue-23046.rs +++ b/src/test/ui/issues/issue-23046.rs @@ -24,7 +24,7 @@ pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>> } fn main() { - let ex = |x| { //~ ERROR type annotations needed + let ex = |x| { let_(add(x,x), |y| { - let_(add(x, x), |x|x)})}; + let_(add(x, x), |x|x)})}; //~ ERROR type annotations needed } diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr index 3e5b4ec91d782..01f7de29c5acd 100644 --- a/src/test/ui/issues/issue-23046.stderr +++ b/src/test/ui/issues/issue-23046.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/issue-23046.rs:27:15 + --> $DIR/issue-23046.rs:29:30 | -LL | let ex = |x| { //~ ERROR type annotations needed - | ^ consider giving this closure parameter a type +LL | let_(add(x, x), |x|x)})}; //~ ERROR type annotations needed + | ^ consider giving this closure parameter a type error: aborting due to previous error From dfe371fa7e1be91b10de952ebf8ee1ea6edd9749 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 17 Sep 2018 05:50:13 +0300 Subject: [PATCH 2/2] rustc_typeck: check well-formedness of type aliases. --- src/Cargo.lock | 19 ++++++++--- src/bootstrap/bin/rustc.rs | 5 +++ src/libgraphviz/lib.rs | 6 ++-- src/librustc/infer/canonical/mod.rs | 8 +++-- src/librustc/lint/builtin.rs | 7 ++++ src/librustc/traits/error_reporting.rs | 14 ++++++++ src/librustc/traits/mod.rs | 4 +++ src/librustc/traits/structural_impls.rs | 3 ++ src/librustc/ty/wf.rs | 9 +++++ src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_data_structures/indexed_vec.rs | 3 +- src/librustc_mir/util/liveness.rs | 3 +- src/librustc_typeck/check/wfcheck.rs | 16 +++++++++ src/test/rustdoc/assoc-item-cast.rs | 4 +-- src/test/rustdoc/const-evalutation-ice.rs | 1 + .../consts/const-eval/pub_const_err-warn.rs | 17 ++++++++++ .../const-eval/pub_const_err-warn.stderr | 14 ++++++++ .../ui/consts/const-eval/pub_const_err.rs | 10 ++---- .../ui/consts/const-eval/pub_const_err.stderr | 34 ++++++++----------- .../const-eval/pub_const_err_bin-warn.rs | 17 ++++++++++ .../const-eval/pub_const_err_bin-warn.stderr | 14 ++++++++ .../ui/consts/const-eval/pub_const_err_bin.rs | 10 ++---- .../const-eval/pub_const_err_bin.stderr | 34 ++++++++----------- .../feature-gate-trivial_bounds.rs | 2 +- .../feature-gate-trivial_bounds.stderr | 11 +++++- src/test/ui/hygiene/assoc_ty_bindings.rs | 8 ++--- src/test/ui/regions/regions-enum-not-wf.rs | 2 +- .../ui/regions/regions-enum-not-wf.stderr | 16 ++++++++- src/test/ui/resolve/issue-3907-2.rs | 1 + src/test/ui/resolve/issue-3907-2.stderr | 14 ++++++-- .../regions-enum-not-wf.rs | 2 +- .../regions-enum-not-wf.stderr | 16 ++++++++- .../ui/structs/struct-path-alias-bounds.rs | 2 +- .../structs/struct-path-alias-bounds.stderr | 17 ++++------ src/test/ui/type/issue-51626.rs | 23 +++++++++++++ src/test/ui/type/issue-51626.stderr | 22 ++++++++++++ src/test/ui/type/type-alias-bounds-err.rs | 25 ++++++++++++++ src/test/ui/type/type-alias-bounds-err.stderr | 24 +++++++++++++ src/test/ui/type/type-alias-bounds.rs | 6 ++-- 39 files changed, 350 insertions(+), 95 deletions(-) create mode 100644 src/test/ui/consts/const-eval/pub_const_err-warn.rs create mode 100644 src/test/ui/consts/const-eval/pub_const_err-warn.stderr create mode 100644 src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs create mode 100644 src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr create mode 100644 src/test/ui/type/issue-51626.rs create mode 100644 src/test/ui/type/issue-51626.stderr create mode 100644 src/test/ui/type/type-alias-bounds-err.rs create mode 100644 src/test/ui/type/type-alias-bounds-err.stderr diff --git a/src/Cargo.lock b/src/Cargo.lock index 9f9c58ef900ee..7331c0e6d8667 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -250,7 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-engine" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -643,6 +643,14 @@ dependencies = [ "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ena" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "env_logger" version = "0.5.12" @@ -1856,7 +1864,7 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", @@ -2122,7 +2130,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2383,7 +2391,7 @@ name = "rustc_traits" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -3126,7 +3134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" "checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" -"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0" +"checksum chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "217042da49c0c0655bbc4aa9f9bed20c7a599429faddc9b2ef3bd09a2769d3ef" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" @@ -3156,6 +3164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee" +"checksum ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25b4e5febb25f08c49f1b07dc33a182729a6b21edfb562b5aef95f78e0dbe5bb" "checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621" "checksum env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d7e69c283751083d53d01eac767407343b8b69c4bd70058e08adc2637cb257" "checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index f30f34acf5c6c..2b8643615d4ab 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -304,6 +304,11 @@ fn main() { { cmd.arg("-Dwarnings"); cmd.arg("-Dbare_trait_objects"); + if !(stage == "0" || target.is_none() && version.is_none()) { + // HACK(eddyb) allow bootstrapping while we're testing with + // the lint on `deny` by default. Remove before merging. + cmd.arg("-Atype_alias_missing_bounds"); + } } if verbose > 1 { diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 9fa48adebdf07..56394b1b07e34 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -574,8 +574,10 @@ impl<'a> LabelText<'a> { } } -pub type Nodes<'a,N> = Cow<'a,[N]>; -pub type Edges<'a,E> = Cow<'a,[E]>; +#[allow(type_alias_bounds)] +pub type Nodes<'a,N: Clone> = Cow<'a,[N]>; +#[allow(type_alias_bounds)] +pub type Edges<'a,E: Clone> = Cow<'a,[E]>; // (The type parameters in GraphWalk should be associated items, // when/if Rust supports such.) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 85aa4f62f214c..e2424b5128db6 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -128,10 +128,12 @@ pub struct QueryResult<'tcx, R> { pub value: R, } -pub type Canonicalized<'gcx, V> = Canonical<'gcx, >::Lifted>; +#[allow(type_alias_bounds)] +pub type Canonicalized<'gcx, V: Lift<'gcx>> = Canonical<'gcx, V::Lifted>; -pub type CanonicalizedQueryResult<'gcx, T> = - Lrc>::Lifted>>>; +#[allow(type_alias_bounds)] +pub type CanonicalizedQueryResult<'gcx, T: Lift<'gcx>> = + Lrc>>; /// Indicates whether or not we were able to prove the query to be /// true. diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e6452ad09278e..87877a087e78a 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -338,6 +338,12 @@ declare_lint! { cannot be referred to by absolute paths" } +declare_lint! { + pub TYPE_ALIAS_MISSING_BOUNDS, + Deny, + "type aliases missing bounds required by the type being aliased, are now deprecated" +} + /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`. pub mod parser { declare_lint! { @@ -406,6 +412,7 @@ impl LintPass for HardwiredLints { PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + TYPE_ALIAS_MISSING_BOUNDS, parser::QUESTION_MARK_MACRO_SEP, ) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8602e7563b8bd..6c04ec12e73e5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -584,6 +584,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::ImplDerivedObligation(data) => { self.get_lint_from_cause_code(&data.parent_code) } + &ObligationCauseCode::TypeAliasMissingBound(id) => { + if self.tcx.sess.rust_2018() { + // Error since Rust 2018. + None + } else { + Some((::lint::builtin::TYPE_ALIAS_MISSING_BOUNDS, id)) + } + } _ => None, } } @@ -1612,6 +1620,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ); } } + ObligationCauseCode::TypeAliasMissingBound(_) => { + err.help("missing bounds in type aliases were previously allowed"); + if !self.tcx.sess.rust_2018() { + err.help("this is a hard error in Rust 2018"); + } + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 485d8041c5ee1..f172690de53e8 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -251,6 +251,10 @@ pub enum ObligationCauseCode<'tcx> { /// #[feature(trivial_bounds)] is not enabled TrivialBound, + + /// `type` alias is missing bounds required by the type being aliased + /// (lint in Rust 2015, error since Rust 2018). + TypeAliasMissingBound(ast::NodeId), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 10e930d1c92d9..7748abd466dc0 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -238,6 +238,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::MethodReceiver => Some(super::MethodReceiver), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), super::TrivialBound => Some(super::TrivialBound), + super::ObligationCauseCode::TypeAliasMissingBound(id) => { + Some(super::ObligationCauseCode::TypeAliasMissingBound(id)) + } } } } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c2bad44db4266..aa286a33cd295 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -140,6 +140,15 @@ enum Elaborate { impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + let code = match self.parent_cause.code { + traits::ObligationCauseCode::TypeAliasMissingBound(_) => { + // FIXME(eddyb) We're not chaining obligation causes here, + // so in the case of cause codes that turn errors into lints, + // we have to replace our cause `code` with the parent one. + self.parent_cause.code.clone() + } + _ => code, + }; traits::ObligationCause::new(self.parent_cause.span, self.parent_cause.body_id, code) } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 5a72fde6a2c8a..b888fa412a6a3 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.9.3" +ena = "0.10.1" log = "0.4" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 2f11fea46d69a..d22b408c09fa1 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -486,7 +486,8 @@ impl fmt::Debug for IndexVec { } } -pub type Enumerated = iter::Map, IntoIdx>; +#[allow(type_alias_bounds)] +pub type Enumerated = iter::Map, IntoIdx>; impl IndexVec { #[inline] diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 3ae470e1d4bbd..cc4c00010d7ea 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -46,7 +46,8 @@ use std::path::{Path, PathBuf}; use transform::MirSource; use util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; -pub type LiveVarSet = IdxSet; +#[allow(type_alias_bounds)] +pub type LiveVarSet = IdxSet; /// This gives the result of the liveness analysis at the boundary of /// basic blocks. diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 33cecb26a4453..ce81ca002a3e1 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -136,6 +136,22 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def vec![] // no implied bounds in a static/const }); } + hir::ItemKind::Ty(ref hir_ty, _) => { + let code = ObligationCauseCode::TypeAliasMissingBound(item.id); + for_item(tcx, item).with_cause_code(code.clone()).with_fcx(|fcx, _this| { + let cause = traits::ObligationCause::new(hir_ty.span, fcx.body_id, code.clone()); + + let def_id = fcx.tcx.hir.local_def_id(item.id); + let ty = fcx.tcx.type_of(def_id); + let item_ty = fcx.inh.normalize_associated_types_in(cause, fcx.param_env, &ty); + + fcx.register_wf_obligation(item_ty, hir_ty.span, code.clone()); + + check_where_clauses(tcx, fcx, item.span, def_id, None, code); + + vec![item_ty] + }); + } hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { check_type_defn(tcx, item, false, |fcx| { vec![fcx.non_enum_variant(struct_def)] diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs index 24f31b5b1040b..f136b6efb5372 100644 --- a/src/test/rustdoc/assoc-item-cast.rs +++ b/src/test/rustdoc/assoc-item-cast.rs @@ -22,5 +22,5 @@ pub trait AsExpression { } // @has foo/type.AsExprOf.html -// @has - '//*[@class="rust typedef"]' 'type AsExprOf = >::Expression;' -pub type AsExprOf = >::Expression; +// @has - '//*[@class="rust typedef"]' 'type AsExprOf, Type> = >::Expression;' +pub type AsExprOf, Type> = >::Expression; diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs index 000ed709a8aae..d9d12ce38f1e8 100644 --- a/src/test/rustdoc/const-evalutation-ice.rs +++ b/src/test/rustdoc/const-evalutation-ice.rs @@ -17,4 +17,5 @@ pub struct S { s: Cell } +#[allow(type_alias_missing_bounds)] // HACK(eddyb) remove before merge pub type _S = [usize; 0 - (mem::size_of::() != 4) as usize]; diff --git a/src/test/ui/consts/const-eval/pub_const_err-warn.rs b/src/test/ui/consts/const-eval/pub_const_err-warn.rs new file mode 100644 index 0000000000000..58e888d5dfa97 --- /dev/null +++ b/src/test/ui/consts/const-eval/pub_const_err-warn.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass +#![warn(const_err)] + +#![crate_type = "lib"] + +pub const Z: u32 = 0 - 1; +//~^ WARN this constant cannot be used diff --git a/src/test/ui/consts/const-eval/pub_const_err-warn.stderr b/src/test/ui/consts/const-eval/pub_const_err-warn.stderr new file mode 100644 index 0000000000000..997b23bfeaed9 --- /dev/null +++ b/src/test/ui/consts/const-eval/pub_const_err-warn.stderr @@ -0,0 +1,14 @@ +warning: this constant cannot be used + --> $DIR/pub_const_err-warn.rs:16:1 + | +LL | pub const Z: u32 = 0 - 1; + | ^^^^^^^^^^^^^^^^^^^-----^ + | | + | attempt to subtract with overflow + | +note: lint level defined here + --> $DIR/pub_const_err-warn.rs:12:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + diff --git a/src/test/ui/consts/const-eval/pub_const_err.rs b/src/test/ui/consts/const-eval/pub_const_err.rs index b7cfa949bac95..92e95c5de8fb6 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.rs +++ b/src/test/ui/consts/const-eval/pub_const_err.rs @@ -8,14 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass -#![warn(const_err)] - #![crate_type = "lib"] -pub const Z: u32 = 0 - 1; -//~^ WARN this constant cannot be used - pub type Foo = [i32; 0 - 1]; -//~^ WARN attempt to subtract with overflow -//~| WARN this array length cannot be used +//~^ ERROR could not evaluate constant expression +//~| attempt to subtract with overflow diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr index fa3a79a5f1790..da2a4409392cf 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err.stderr @@ -1,26 +1,22 @@ -warning: this constant cannot be used - --> $DIR/pub_const_err.rs:16:1 - | -LL | pub const Z: u32 = 0 - 1; - | ^^^^^^^^^^^^^^^^^^^-----^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/pub_const_err.rs:12:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: attempt to subtract with overflow - --> $DIR/pub_const_err.rs:19:22 +error: attempt to subtract with overflow + --> $DIR/pub_const_err.rs:13:22 | LL | pub type Foo = [i32; 0 - 1]; | ^^^^^ + | + = note: #[deny(const_err)] on by default -warning: this array length cannot be used - --> $DIR/pub_const_err.rs:19:22 +error: could not evaluate constant expression + --> $DIR/pub_const_err.rs:13:16 | LL | pub type Foo = [i32; 0 - 1]; - | ^^^^^ attempt to subtract with overflow + | ^^^^^^-----^ + | | + | attempt to subtract with overflow + | + = note: #[deny(type_alias_missing_bounds)] on by default + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs new file mode 100644 index 0000000000000..5a035711f8647 --- /dev/null +++ b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass +#![warn(const_err)] + +pub const Z: u32 = 0 - 1; +//~^ WARN this constant cannot be used + +fn main() {} diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr new file mode 100644 index 0000000000000..db0bf9e5fe679 --- /dev/null +++ b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr @@ -0,0 +1,14 @@ +warning: this constant cannot be used + --> $DIR/pub_const_err_bin-warn.rs:14:1 + | +LL | pub const Z: u32 = 0 - 1; + | ^^^^^^^^^^^^^^^^^^^-----^ + | | + | attempt to subtract with overflow + | +note: lint level defined here + --> $DIR/pub_const_err_bin-warn.rs:12:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.rs b/src/test/ui/consts/const-eval/pub_const_err_bin.rs index bafa5b2f4da12..ad11ae255eaa6 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.rs +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.rs @@ -8,14 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass -#![warn(const_err)] - -pub const Z: u32 = 0 - 1; -//~^ WARN this constant cannot be used - pub type Foo = [i32; 0 - 1]; -//~^ WARN attempt to subtract with overflow -//~| WARN this array length cannot be used +//~^ ERROR could not evaluate constant expression +//~| attempt to subtract with overflow fn main() {} diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr index 73229c60d14db..3e36a0afff27e 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr @@ -1,26 +1,22 @@ -warning: this constant cannot be used - --> $DIR/pub_const_err_bin.rs:14:1 - | -LL | pub const Z: u32 = 0 - 1; - | ^^^^^^^^^^^^^^^^^^^-----^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/pub_const_err_bin.rs:12:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: attempt to subtract with overflow - --> $DIR/pub_const_err_bin.rs:17:22 +error: attempt to subtract with overflow + --> $DIR/pub_const_err_bin.rs:11:22 | LL | pub type Foo = [i32; 0 - 1]; | ^^^^^ + | + = note: #[deny(const_err)] on by default -warning: this array length cannot be used - --> $DIR/pub_const_err_bin.rs:17:22 +error: could not evaluate constant expression + --> $DIR/pub_const_err_bin.rs:11:16 | LL | pub type Foo = [i32; 0 - 1]; - | ^^^^^ attempt to subtract with overflow + | ^^^^^^-----^ + | | + | attempt to subtract with overflow + | + = note: #[deny(type_alias_missing_bounds)] on by default + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs index dba66e0b69bfc..c7e9155fc9fca 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -25,7 +25,7 @@ trait T where i32: Foo {} //~ ERROR union U where i32: Foo { f: i32 } //~ ERROR -type Y where i32: Foo = (); // OK - bound is ignored +type Y where i32: Foo = (); //~ ERROR impl Foo for () where i32: Foo { //~ ERROR fn test(&self) { diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index f20c1ebb37aa9..9d43b6cc79d57 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -34,6 +34,15 @@ LL | union U where i32: Foo { f: i32 } //~ ERROR = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable +error[E0277]: the trait bound `i32: Foo` is not satisfied + --> $DIR/feature-gate-trivial_bounds.rs:28:1 + | +LL | type Y where i32: Foo = (); //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` + | + = help: see issue #48214 + = help: add #![feature(trivial_bounds)] to the crate attributes to enable + error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:30:1 | @@ -125,6 +134,6 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs index 46a138749ff17..e0a04c43da5e5 100644 --- a/src/test/ui/hygiene/assoc_ty_bindings.rs +++ b/src/test/ui/hygiene/assoc_ty_bindings.rs @@ -15,10 +15,10 @@ trait Base { type AssocTy; - fn f(); + fn f(&self); } trait Derived: Base { - fn g(); + fn g(&self); } macro mac() { @@ -27,12 +27,12 @@ macro mac() { impl Base for u8 { type AssocTy = u8; - fn f() { + fn f(&self) { let _: Self::AssocTy; } } impl Derived for u8 { - fn g() { + fn g(&self) { let _: Self::AssocTy; } } diff --git a/src/test/ui/regions/regions-enum-not-wf.rs b/src/test/ui/regions/regions-enum-not-wf.rs index a2d3cf6779f17..524a07de80d4f 100644 --- a/src/test/ui/regions/regions-enum-not-wf.rs +++ b/src/test/ui/regions/regions-enum-not-wf.rs @@ -22,7 +22,7 @@ where T: 'a { type Out = (); } -type RequireOutlives<'a, T> = >::Out; +type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough enum Ref1<'a, T> { Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr index 923ea17622ac0..384bb6a8748b5 100644 --- a/src/test/ui/regions/regions-enum-not-wf.stderr +++ b/src/test/ui/regions/regions-enum-not-wf.stderr @@ -1,3 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:25:31 + | +LL | type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough + | - ^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider adding an explicit lifetime bound `T: 'a`... + | +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/regions-enum-not-wf.rs:25:31 + | +LL | type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ + error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:28:18 | @@ -62,6 +76,6 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/resolve/issue-3907-2.rs b/src/test/ui/resolve/issue-3907-2.rs index 130647966f2d1..7a76e020da521 100644 --- a/src/test/ui/resolve/issue-3907-2.rs +++ b/src/test/ui/resolve/issue-3907-2.rs @@ -12,6 +12,7 @@ extern crate issue_3907; type Foo = issue_3907::Foo+'static; +//~^ ERROR E0038 struct S { name: isize diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr index 567fd31b09ca3..8a61415aae6e5 100644 --- a/src/test/ui/resolve/issue-3907-2.stderr +++ b/src/test/ui/resolve/issue-3907-2.stderr @@ -1,11 +1,21 @@ error[E0038]: the trait `issue_3907::Foo` cannot be made into an object - --> $DIR/issue-3907-2.rs:20:1 + --> $DIR/issue-3907-2.rs:14:12 + | +LL | type Foo = issue_3907::Foo+'static; + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object + | + = note: method `bar` has no receiver + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error[E0038]: the trait `issue_3907::Foo` cannot be made into an object + --> $DIR/issue-3907-2.rs:21:1 | LL | fn bar(_x: Foo) {} | ^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object | = note: method `bar` has no receiver -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs index a2d3cf6779f17..524a07de80d4f 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs @@ -22,7 +22,7 @@ where T: 'a { type Out = (); } -type RequireOutlives<'a, T> = >::Out; +type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough enum Ref1<'a, T> { Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 923ea17622ac0..384bb6a8748b5 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -1,3 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/regions-enum-not-wf.rs:25:31 + | +LL | type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough + | - ^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider adding an explicit lifetime bound `T: 'a`... + | +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/regions-enum-not-wf.rs:25:31 + | +LL | type RequireOutlives<'a, T> = >::Out; //~ ERROR the parameter type `T` may not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ + error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:28:18 | @@ -62,6 +76,6 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs index 1b6e51e37034e..d41cb9694761b 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.rs +++ b/src/test/ui/structs/struct-path-alias-bounds.rs @@ -14,8 +14,8 @@ struct S { a: T } struct NoClone; type A = S; +//~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied fn main() { let s = A { a: NoClone }; - //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied } diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr index f8e2fe1410f6c..8ed4282b66a0d 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.stderr +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -1,15 +1,12 @@ -error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied - --> $DIR/struct-path-alias-bounds.rs:19:13 +error: the trait bound `NoClone: std::clone::Clone` is not satisfied + --> $DIR/struct-path-alias-bounds.rs:16:10 | -LL | let s = A { a: NoClone }; - | ^ the trait `std::clone::Clone` is not implemented for `NoClone` +LL | type A = S; + | ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `NoClone` | -note: required by `S` - --> $DIR/struct-path-alias-bounds.rs:13:1 - | -LL | struct S { a: T } - | ^^^^^^^^^^^^^^^^^^ + = note: #[deny(type_alias_missing_bounds)] on by default + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type/issue-51626.rs b/src/test/ui/type/issue-51626.rs new file mode 100644 index 0000000000000..f8c7a5f6b14f7 --- /dev/null +++ b/src/test/ui/type/issue-51626.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Trait {} + +pub struct Foo(T); + +pub struct Qux; + +pub type Bar = Foo; +//~^ ERROR the trait bound `T: Trait` is not satisfied + +pub type Baz = Foo; +//~^ ERROR the trait bound `Qux: Trait` is not satisfied + +fn main() {} diff --git a/src/test/ui/type/issue-51626.stderr b/src/test/ui/type/issue-51626.stderr new file mode 100644 index 0000000000000..7debf69fa196a --- /dev/null +++ b/src/test/ui/type/issue-51626.stderr @@ -0,0 +1,22 @@ +error: the trait bound `T: Trait` is not satisfied + --> $DIR/issue-51626.rs:17:25 + | +LL | pub type Bar = Foo; + | ^^^^^^ the trait `Trait` is not implemented for `T` + | + = note: #[deny(type_alias_missing_bounds)] on by default + = help: consider adding a `where T: Trait` bound + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: the trait bound `Qux: Trait` is not satisfied + --> $DIR/issue-51626.rs:20:1 + | +LL | pub type Baz = Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Qux` + | + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/type/type-alias-bounds-err.rs b/src/test/ui/type/type-alias-bounds-err.rs new file mode 100644 index 0000000000000..6676561bcbf7a --- /dev/null +++ b/src/test/ui/type/type-alias-bounds-err.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +// This test contains examples originally in `type-alias-bounds.rs`, +// that now produce errors instead of being silently accepted. + +// Bounds are not checked either, i.e. the definition is not necessarily well-formed +struct Sendable(T); +type MySendable = Sendable; +//~^ ERROR `T` cannot be sent between threads safely + +trait Bound { type Assoc; } +type T4 = ::Assoc; +//~^ ERROR the trait bound `U: Bound` is not satisfied + +fn main() {} diff --git a/src/test/ui/type/type-alias-bounds-err.stderr b/src/test/ui/type/type-alias-bounds-err.stderr new file mode 100644 index 0000000000000..342a58661a48d --- /dev/null +++ b/src/test/ui/type/type-alias-bounds-err.stderr @@ -0,0 +1,24 @@ +error: `T` cannot be sent between threads safely + --> $DIR/type-alias-bounds-err.rs:18:22 + | +LL | type MySendable = Sendable; + | ^^^^^^^^^^^ `T` cannot be sent between threads safely + | + = note: #[deny(type_alias_missing_bounds)] on by default + = help: the trait `std::marker::Send` is not implemented for `T` + = help: consider adding a `where T: std::marker::Send` bound + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: the trait bound `U: Bound` is not satisfied + --> $DIR/type-alias-bounds-err.rs:22:14 + | +LL | type T4 = ::Assoc; + | ^^^^^^^^^^^^^^^^^^^ the trait `Bound` is not implemented for `U` + | + = help: consider adding a `where U: Bound` bound + = help: missing bounds in type aliases were previously allowed + = help: this is a hard error in Rust 2018 + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/type/type-alias-bounds.rs b/src/test/ui/type/type-alias-bounds.rs index a17bb9e952d3c..60171251f8aeb 100644 --- a/src/test/ui/type/type-alias-bounds.rs +++ b/src/test/ui/type/type-alias-bounds.rs @@ -49,8 +49,8 @@ fn foo<'a>(y: &'a i32) { } // Bounds are not checked either, i.e. the definition is not necessarily well-formed -struct Sendable(T); -type MySendable = Sendable; // no error here! +// struct Sendable(T); // NOTE(eddyb) moved to `type-alias-bounds-err.rs` +// type MySendable = Sendable; // no error here! // However, bounds *are* taken into account when accessing associated types trait Bound { type Assoc; } @@ -60,7 +60,7 @@ type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases // This errors // type T3 = U::Assoc; // Do this instead -type T4 = ::Assoc; +// type T4 = ::Assoc; // NOTE(eddyb) moved to `type-alias-bounds-err.rs` // Make sure the help about associatd types is not shown incorrectly type T5 = ::Assoc; //~ WARN not enforced in type aliases