]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #45668 - nikomatsakis:nll-free-region, r=arielb1
authorbors <bors@rust-lang.org>
Mon, 6 Nov 2017 23:30:57 +0000 (23:30 +0000)
committerbors <bors@rust-lang.org>
Mon, 6 Nov 2017 23:30:57 +0000 (23:30 +0000)
extend NLL with preliminary support for free regions on functions

This PR extends https://github.com/rust-lang/rust/pull/45538 with support for free regions. This is pretty preliminary and will no doubt want to change in various ways, particularly as we add support for closures, but it's enough to get the basic idea in place:

- We now create specific regions to represent each named lifetime declared on the function.
- Region values can contain references to these regions (represented for now as a `BTreeSet<RegionIndex>`).
- If we wind up trying to infer that `'a: 'b` must hold, but no such relationship was declared, we report an error.

It also does a number of drive-by refactorings.

r? @arielb1

cc @spastorino

1  2 
src/librustc/infer/error_reporting/mod.rs
src/librustc/mir/visit.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/mir_stats.rs

index aac67b528c2d08d3b6a2b28d21d8a38c4bc407e1,5d0a6ae98d7a69128805e5f9da48be49a2afa13c..e9916bd77e7582ea59880046bd41e4a0fe468653
@@@ -66,7 -66,7 +66,7 @@@ use hir::map as hir_map
  use hir::def_id::DefId;
  use middle::region;
  use traits::{ObligationCause, ObligationCauseCode};
 -use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
 +use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
  use ty::error::TypeError;
  use syntax::ast::DUMMY_NODE_ID;
  use syntax_pos::{Pos, Span};
@@@ -262,6 -262,27 +262,27 @@@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx
                                  errors: &Vec<RegionResolutionError<'tcx>>) {
          debug!("report_region_errors(): {} errors to start", errors.len());
  
+         if self.tcx.sess.opts.debugging_opts.nll {
+             for error in errors {
+                 match *error {
+                     RegionResolutionError::ConcreteFailure(ref origin, ..) |
+                     RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
+                         self.tcx.sess.span_warn(
+                             origin.span(),
+                             "not reporting region error due to -Znll");
+                     }
+                     RegionResolutionError::SubSupConflict(ref rvo, ..) => {
+                         self.tcx.sess.span_warn(
+                             rvo.span(),
+                             "not reporting region error due to -Znll");
+                     }
+                 }
+             }
+             return;
+         }
          // try to pre-process the errors, which will group some of them
          // together into a `ProcessedErrors` group:
          let errors = self.process_errors(errors);
                           values: Option<ValuePairs<'tcx>>,
                           terr: &TypeError<'tcx>)
      {
 -        let (expected_found, is_simple_error) = match values {
 -            None => (None, false),
 +        let (expected_found, exp_found, is_simple_error) = match values {
 +            None => (None, None, false),
              Some(values) => {
 -                let is_simple_error = match values {
 +                let (is_simple_error, exp_found) = match values {
                      ValuePairs::Types(exp_found) => {
 -                        exp_found.expected.is_primitive() && exp_found.found.is_primitive()
 +                        let is_simple_err = exp_found.expected.is_primitive()
 +                            && exp_found.found.is_primitive();
 +
 +                        (is_simple_err, Some(exp_found))
                      }
 -                    _ => false,
 +                    _ => (false, None),
                  };
                  let vals = match self.values_str(&values) {
                      Some((expected, found)) => Some((expected, found)),
                          return
                      }
                  };
 -                (vals, is_simple_error)
 +                (vals, exp_found, is_simple_error)
              }
          };
  
          let span = cause.span;
  
 +        diag.span_label(span, terr.to_string());
 +        if let Some((sp, msg)) = secondary_span {
 +            diag.span_label(sp, msg);
 +        }
 +
          if let Some((expected, found)) = expected_found {
              match (terr, is_simple_error, expected == found) {
                  (&TypeError::Sorts(ref values), false, true) => {
                          &format!(" ({})", values.expected.sort_string(self.tcx)),
                          &format!(" ({})", values.found.sort_string(self.tcx)));
                  }
 -                (_, false,  _) => {
 +                (_, false, _) => {
 +                    if let Some(exp_found) = exp_found {
 +                        let (def_id, ret_ty) = match exp_found.found.sty {
 +                            TypeVariants::TyFnDef(def, _) => {
 +                                (Some(def), Some(self.tcx.fn_sig(def).output()))
 +                            }
 +                            _ => (None, None)
 +                        };
 +
 +                        let exp_is_struct = match exp_found.expected.sty {
 +                            TypeVariants::TyAdt(def, _) => def.is_struct(),
 +                            _ => false
 +                        };
 +
 +                        if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) {
 +                            if exp_is_struct && exp_found.expected == ret_ty.0 {
 +                                let message = format!(
 +                                    "did you mean `{}(/* fields */)`?",
 +                                    self.tcx.item_path_str(def_id)
 +                                );
 +                                diag.span_label(cause.span, message);
 +                            }
 +                        }
 +                    }
 +
                      diag.note_expected_found(&"type", expected, found);
                  }
                  _ => (),
              }
          }
  
 -        diag.span_label(span, terr.to_string());
 -        if let Some((sp, msg)) = secondary_span {
 -            diag.span_label(sp, msg);
 -        }
 -
          self.note_error_origin(diag, &cause);
          self.check_and_note_conflicting_crates(diag, terr, span);
          self.tcx.note_and_explain_type_err(diag, terr, span);
index 47dbcee6394253b167b353541ce51b4d97bc1d9e,2d9d3643ff69d69aafdf498d33447cbc4606bb75..00863abc84deeb61b4e5652aadbdb399b34895fc
@@@ -209,7 -209,7 +209,7 @@@ macro_rules! make_mir_visitor 
  
              fn visit_ty(&mut self,
                          ty: & $($mutability)* Ty<'tcx>,
-                         _: Lookup) {
+                         _: TyContext) {
                  self.super_ty(ty);
              }
  
              }
  
              fn visit_local_decl(&mut self,
+                                 local: Local,
                                  local_decl: & $($mutability)* LocalDecl<'tcx>) {
-                 self.super_local_decl(local_decl);
+                 self.super_local_decl(local, local_decl);
              }
  
              fn visit_local(&mut self,
                      self.visit_visibility_scope_data(scope);
                  }
  
-                 let lookup = Lookup::Src(SourceInfo {
+                 let lookup = TyContext::SourceInfo(SourceInfo {
                      span: mir.span,
                      scope: ARGUMENT_VISIBILITY_SCOPE,
                  });
                  self.visit_ty(&$($mutability)* mir.return_ty, lookup);
  
-                 for local_decl in &$($mutability)* mir.local_decls {
-                     self.visit_local_decl(local_decl);
+                 for local in mir.local_decls.indices() {
+                     self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
                  }
  
                  self.visit_span(&$($mutability)* mir.span);
                          for operand in lvalues {
                              self.visit_lvalue(& $($mutability)* operand.lval,
                                                LvalueContext::Validate, location);
-                             self.visit_ty(& $($mutability)* operand.ty, Lookup::Loc(location));
+                             self.visit_ty(& $($mutability)* operand.ty,
+                                           TyContext::Location(location));
                          }
                      }
                      StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
                                                  ref values,
                                                  ref targets } => {
                          self.visit_operand(discr, source_location);
-                         self.visit_ty(switch_ty, Lookup::Loc(source_location));
+                         self.visit_ty(switch_ty, TyContext::Location(source_location));
                          for value in &values[..] {
                              self.visit_const_int(value, source_location);
                          }
                          self.visit_operand(value, source_location);
                          self.visit_branch(block, resume);
                          drop.map(|t| self.visit_branch(block, t));
 +
                      }
  
 +                    TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
 +                        self.visit_branch(block, real_target);
 +                        for target in imaginary_targets {
 +                            self.visit_branch(block, *target);
 +                        }
 +                    }
                  }
              }
  
                                   ref $($mutability)* operand,
                                   ref $($mutability)* ty) => {
                          self.visit_operand(operand, location);
-                         self.visit_ty(ty, Lookup::Loc(location));
+                         self.visit_ty(ty, TyContext::Location(location));
                      }
  
                      Rvalue::BinaryOp(_bin_op,
                      }
  
                      Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
-                         self.visit_ty(ty, Lookup::Loc(location));
+                         self.visit_ty(ty, TyContext::Location(location));
                      }
  
                      Rvalue::Aggregate(ref $($mutability)* kind,
                          let kind = &$($mutability)* **kind;
                          match *kind {
                              AggregateKind::Array(ref $($mutability)* ty) => {
-                                 self.visit_ty(ty, Lookup::Loc(location));
+                                 self.visit_ty(ty, TyContext::Location(location));
                              }
                              AggregateKind::Tuple => {
                              }
                      ref $($mutability)* ty,
                  } = *static_;
                  self.visit_def_id(def_id, location);
-                 self.visit_ty(ty, Lookup::Loc(location));
+                 self.visit_ty(ty, TyContext::Location(location));
              }
  
              fn super_projection(&mut self,
                      ProjectionElem::Subslice { from: _, to: _ } => {
                      }
                      ProjectionElem::Field(_field, ref $($mutability)* ty) => {
-                         self.visit_ty(ty, Lookup::Loc(location));
+                         self.visit_ty(ty, TyContext::Location(location));
                      }
                      ProjectionElem::Index(ref $($mutability)* local) => {
                          self.visit_local(local, LvalueContext::Consume, location);
              }
  
              fn super_local_decl(&mut self,
+                                 local: Local,
                                  local_decl: & $($mutability)* LocalDecl<'tcx>) {
                  let LocalDecl {
                      mutability: _,
                      is_user_variable: _,
                  } = *local_decl;
  
-                 self.visit_ty(ty, Lookup::Src(*source_info));
+                 self.visit_ty(ty, TyContext::LocalDecl {
+                     local,
+                     source_info: *source_info,
+                 });
                  self.visit_source_info(source_info);
                  self.visit_visibility_scope(lexical_scope);
              }
                  } = *constant;
  
                  self.visit_span(span);
-                 self.visit_ty(ty, Lookup::Loc(location));
+                 self.visit_ty(ty, TyContext::Location(location));
                  self.visit_literal(literal, location);
              }
  
  make_mir_visitor!(Visitor,);
  make_mir_visitor!(MutVisitor,mut);
  
+ /// Extra information passed to `visit_ty` and friends to give context
+ /// about where the type etc appears.
  #[derive(Copy, Clone, Debug)]
- pub enum Lookup {
-     Loc(Location),
-     Src(SourceInfo),
+ pub enum TyContext {
+     LocalDecl {
+         /// The index of the local variable we are visiting.
+         local: Local,
+         /// The source location where this local variable was declared.
+         source_info: SourceInfo,
+     },
+     Location(Location),
+     SourceInfo(SourceInfo),
  }
  
  #[derive(Copy, Clone, Debug, PartialEq, Eq)]
index d8dc7a8d5cc7d3e57f377828295f4bfd900a61a7,d238b145d424c32195f8542f74430d9f52c73348..b07e818ee87525045e6d237d575d74cb66117cef
@@@ -92,8 -92,8 +92,8 @@@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> 
          self.sanitize_type(rvalue, rval_ty);
      }
  
-     fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
-         self.super_local_decl(local_decl);
+     fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
+         self.super_local_decl(local, local_decl);
          self.sanitize_type(local_decl, local_decl.ty);
      }
  
@@@ -441,8 -441,7 +441,8 @@@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'g
              TerminatorKind::Return |
              TerminatorKind::GeneratorDrop |
              TerminatorKind::Unreachable |
 -            TerminatorKind::Drop { .. } => {
 +            TerminatorKind::Drop { .. } |
 +            TerminatorKind::FalseEdges { .. } => {
                  // no checks needed for these
              }
  
                      self.assert_iscleanup(mir, block, cleanup, true);
                  }
              }
 +            TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
 +                self.assert_iscleanup(mir, block, real_target, is_cleanup);
 +                for target in imaginary_targets {
 +                    self.assert_iscleanup(mir, block, *target, is_cleanup);
 +                }
 +            }
          }
      }
  
index 30e2ba61dbda7ef90b50b4c6fd5605562f517a78,3f75c6385223e0094019dee5c12e2e7842cba56b..ab41ad1e0995056c46635618869377fffad65af6
@@@ -14,7 -14,7 +14,7 @@@
  
  use rustc_const_math::{ConstUsize};
  use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
- use rustc::mir::{Constant, Literal, Location, LocalDecl};
+ use rustc::mir::{Constant, Literal, Location, Local, LocalDecl};
  use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
  use rustc::mir::{Mir, Operand, ProjectionElem};
  use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
@@@ -121,7 -121,6 +121,7 @@@ impl<'a, 'tcx> mir_visit::Visitor<'tcx
              TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
              TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
              TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
 +            TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
          }, kind);
          self.super_terminator_kind(block, kind, location);
      }
      }
  
      fn visit_local_decl(&mut self,
+                         local: Local,
                          local_decl: &LocalDecl<'tcx>) {
          self.record("LocalDecl", local_decl);
-         self.super_local_decl(local_decl);
+         self.super_local_decl(local, local_decl);
      }
  
      fn visit_visibility_scope(&mut self,