Skip to content

Commit

Permalink
Auto merge of #46862 - nikomatsakis:nll-master, r=arielb1
Browse files Browse the repository at this point in the history
NLL feature complete (adds `feature(nll)`)!

This is the final PR for the nll-master branch; it brings over all remaining content.

The contents of the branch include:

- track causal information and use it to report extended errors
- handle `impl Trait` in NLL code
- improve printing of outlives errors
- add `#![feature(nll)]` and some more sample tests

The commits should for the most part build independently.

r? @pnkfelix (and/or @arielb1)
  • Loading branch information
bors committed Dec 20, 2017
2 parents 7eb64b8 + d925f4d commit fdfb007
Show file tree
Hide file tree
Showing 139 changed files with 4,132 additions and 1,844 deletions.
626 changes: 626 additions & 0 deletions src/librustc/infer/anon_types/mod.rs

Large diffs are not rendered by default.

415 changes: 0 additions & 415 deletions src/librustc/infer/error_reporting/different_lifetimes.rs

This file was deleted.

57 changes: 35 additions & 22 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ mod note;

mod need_type_info;

mod named_anon_conflict;
#[macro_use]
mod util;
mod different_lifetimes;
pub mod nice_region_error;

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn note_and_explain_region(self,
Expand Down Expand Up @@ -261,10 +258,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_region_errors(&self,
region_scope_tree: &region::ScopeTree,
errors: &Vec<RegionResolutionError<'tcx>>) {
errors: &Vec<RegionResolutionError<'tcx>>,
will_later_be_reported_by_nll: bool) {
debug!("report_region_errors(): {} errors to start", errors.len());

if self.tcx.sess.opts.debugging_opts.nll {
if will_later_be_reported_by_nll && self.tcx.sess.nll() {
// With `#![feature(nll)]`, we want to present a nice user
// experience, so don't even mention the errors from the
// AST checker.
if self.tcx.sess.features.borrow().nll {
return;
}

// But with -Znll, it's nice to have some note for later.
for error in errors {
match *error {
RegionResolutionError::ConcreteFailure(ref origin, ..) |
Expand Down Expand Up @@ -294,9 +300,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
for error in errors {
debug!("report_region_errors: error = {:?}", error);

if !self.try_report_named_anon_conflict(&error) &&
!self.try_report_anon_anon_conflict(&error)
{
if !self.try_report_nice_region_error(&error) {
match error.clone() {
// These errors could indicate all manner of different
// problems with many different solutions. Rather
Expand All @@ -309,8 +313,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.report_concrete_failure(region_scope_tree, origin, sub, sup).emit();
}

RegionResolutionError::GenericBoundFailure(kind, param_ty, sub) => {
self.report_generic_bound_failure(region_scope_tree, kind, param_ty, sub);
RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
self.report_generic_bound_failure(
region_scope_tree,
origin.span(),
Some(origin),
param_ty,
sub,
);
}

RegionResolutionError::SubSupConflict(var_origin,
Expand Down Expand Up @@ -906,11 +916,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
DiagnosticStyledString::highlighted(format!("{}", exp_found.found))))
}

fn report_generic_bound_failure(&self,
region_scope_tree: &region::ScopeTree,
origin: SubregionOrigin<'tcx>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>)
pub fn report_generic_bound_failure(&self,
region_scope_tree: &region::ScopeTree,
span: Span,
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>)
{
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
Expand Down Expand Up @@ -958,9 +969,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
format!("the associated type `{}`", p),
};

if let SubregionOrigin::CompareImplMethodObligation {
if let Some(SubregionOrigin::CompareImplMethodObligation {
span, item_name, impl_item_def_id, trait_item_def_id,
} = origin {
}) = origin {
self.report_extra_impl_obligation(span,
item_name,
impl_item_def_id,
Expand Down Expand Up @@ -995,7 +1006,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(self.tcx.sess,
origin.span(),
span,
E0309,
"{} may not live long enough",
labeled_user_string);
Expand All @@ -1006,7 +1017,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::ReStatic => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(self.tcx.sess,
origin.span(),
span,
E0310,
"{} may not live long enough",
labeled_user_string);
Expand All @@ -1017,7 +1028,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
_ => {
// If not, be less specific.
let mut err = struct_span_err!(self.tcx.sess,
origin.span(),
span,
E0311,
"{} may not live long enough",
labeled_user_string);
Expand All @@ -1033,7 +1044,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
};

self.note_region_origin(&mut err, &origin);
if let Some(origin) = origin {
self.note_region_origin(&mut err, &origin);
}
err.emit();
}

Expand Down
101 changes: 0 additions & 101 deletions src/librustc/infer/error_reporting/named_anon_conflict.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright 2012-2013 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Error Reporting for Anonymous Region Lifetime Errors
//! where both the regions are anonymous.

use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::error_reporting::nice_region_error::util::AnonymousArgInfo;
use util::common::ErrorReported;

impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
///
/// Consider a case where we have
///
/// ```no_run
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
/// x.push(y);
/// }
/// ```
///
/// The example gives
///
/// ```text
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
/// --- --- these references are declared with different lifetimes...
/// x.push(y);
/// ^ ...but data from `y` flows into `x` here
/// ```
///
/// It has been extended for the case of structs too.
///
/// Consider the example
///
/// ```no_run
/// struct Ref<'a> { x: &'a u32 }
/// ```
///
/// ```text
/// fn foo(mut x: Vec<Ref>, y: Ref) {
/// --- --- these structs are declared with different lifetimes...
/// x.push(y);
/// ^ ...but data from `y` flows into `x` here
/// }
/// ````
///
/// It will later be extended to trait objects.
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
let NiceRegionError { span, sub, sup, .. } = *self;

// Determine whether the sub and sup consist of both anonymous (elided) regions.
let anon_reg_sup = self.is_suitable_region(sup)?;

let anon_reg_sub = self.is_suitable_region(sub)?;
let scope_def_id_sup = anon_reg_sup.def_id;
let bregion_sup = anon_reg_sup.boundregion;
let scope_def_id_sub = anon_reg_sub.def_id;
let bregion_sub = anon_reg_sub.boundregion;

let ty_sup = self.find_anon_type(sup, &bregion_sup)?;

let ty_sub = self.find_anon_type(sub, &bregion_sub)?;

debug!(
"try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
ty_sub,
sup,
bregion_sup
);
debug!(
"try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
ty_sup,
sub,
bregion_sub
);

let (ty_sup, ty_fndecl_sup) = ty_sup;
let (ty_sub, ty_fndecl_sub) = ty_sub;

let AnonymousArgInfo {
arg: anon_arg_sup, ..
} = self.find_arg_with_region(sup, sup)?;
let AnonymousArgInfo {
arg: anon_arg_sub, ..
} = self.find_arg_with_region(sub, sub)?;

let sup_is_ret_type =
self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
let sub_is_ret_type =
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);

let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() {
format!(" from `{}`", simple_name)
} else {
format!("")
};

let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() {
format!(" into `{}`", simple_name)
} else {
format!("")
};


let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
(None, None) => {
let (main_label_1, span_label_1) = if ty_sup == ty_sub {
(
format!("this type is declared with multiple lifetimes..."),
format!(
"...but data{} flows{} here",
format!(" with one lifetime"),
format!(" into the other")
),
)
} else {
(
format!("these two types are declared with different lifetimes..."),
format!(
"...but data{} flows{} here",
span_label_var1,
span_label_var2
),
)
};
(ty_sup.span, ty_sub.span, main_label_1, span_label_1)
}

(Some(ret_span), _) => (
ty_sub.span,
ret_span,
format!(
"this parameter and the return type are declared \
with different lifetimes...",
),
format!("...but data{} is returned here", span_label_var1),
),
(_, Some(ret_span)) => (
ty_sup.span,
ret_span,
format!(
"this parameter and the return type are declared \
with different lifetimes...",
),
format!("...but data{} is returned here", span_label_var1),
),
};


struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch")
.span_label(span_1, main_label)
.span_label(span_2, format!(""))
.span_label(span, span_label)
.emit();
return Some(ErrorReported);
}
}
Loading

0 comments on commit fdfb007

Please sign in to comment.