]> git.lizzy.rs Git - rust.git/commitdiff
make lifetimes that only appear in return type early-bound
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 6 Jan 2017 19:35:23 +0000 (14:35 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sun, 5 Feb 2017 21:30:03 +0000 (16:30 -0500)
This is the full and proper fix for #32330. This also makes some effort
to give a nice error message (as evidenced by the `ui` test), sending
users over to the tracking issue for a full explanation.

21 files changed:
src/librustc/infer/error_reporting.rs
src/librustc/infer/higher_ranked/mod.rs
src/librustc/infer/mod.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc/util/ppaux.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/clean/mod.rs
src/test/compile-fail/E0582.rs [new file with mode: 0644]
src/test/compile-fail/associated-types/bound-lifetime-constrained.rs
src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs
src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs
src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs [deleted file]
src/test/compile-fail/regions-fn-subtyping-return-static.rs
src/test/ui/regions-fn-subtyping-return-static.rs [new file with mode: 0644]
src/test/ui/regions-fn-subtyping-return-static.stderr [new file with mode: 0644]

index 2489a6a6c7a6304e46d552a86112f2ce68d15a22..939f214407ef71606d58d90ec7af381e663e816f 100644 (file)
 use hir::map as hir_map;
 use hir;
 
-use lint;
 use hir::def_id::DefId;
 use infer;
 use middle::region;
 use traits::{ObligationCause, ObligationCauseCode};
 use ty::{self, TyCtxt, TypeFoldable};
-use ty::{Region, ReFree};
+use ty::{Region, ReFree, Issue32330};
 use ty::error::TypeError;
 
 use std::fmt;
@@ -610,6 +609,39 @@ pub fn note_type_err(&self,
         self.tcx.note_and_explain_type_err(diag, terr, span);
     }
 
+    pub fn note_issue_32330(&self,
+                            diag: &mut DiagnosticBuilder<'tcx>,
+                            terr: &TypeError<'tcx>)
+    {
+        debug!("note_issue_32330: terr={:?}", terr);
+        match *terr {
+            TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) |
+            TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => {
+                match self.region_vars.var_origin(vid) {
+                    RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 {
+                        fn_def_id,
+                        region_name
+                    })) => {
+                        diag.note(
+                            &format!("lifetime parameter `{0}` declared on fn `{1}` \
+                                      appears only in the return type, \
+                                      but here is required to be higher-ranked, \
+                                      which means that `{0}` must appear in both \
+                                      argument and return types",
+                                     region_name,
+                                     self.tcx.item_path_str(fn_def_id)));
+                        diag.note(
+                            &format!("this error is the result of a recent bug fix; \
+                                      for more information, see issue #33685 \
+                                      <https://github.com/rust-lang/rust/issues/33685>"));
+                    }
+                    _ => { }
+                }
+            }
+            _ => { }
+        }
+    }
+
     pub fn report_and_explain_type_error(&self,
                                          trace: TypeTrace<'tcx>,
                                          terr: &TypeError<'tcx>)
@@ -629,6 +661,7 @@ pub fn report_and_explain_type_error(&self,
             }
         };
         self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
+        self.note_issue_32330(&mut diag, terr);
         diag
     }
 
@@ -1053,27 +1086,6 @@ fn report_processed_errors(&self,
             err.emit();
         }
     }
-
-    pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
-        for issue32330 in issue32330s {
-            match *issue32330 {
-                ty::Issue32330::WontChange => { }
-                ty::Issue32330::WillChange { fn_def_id, region_name } => {
-                    self.tcx.sess.add_lint(
-                        lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
-                        ast::CRATE_NODE_ID,
-                        span,
-                        format!("lifetime parameter `{0}` declared on fn `{1}` \
-                                 appears only in the return type, \
-                                 but here is required to be higher-ranked, \
-                                 which means that `{0}` must appear in both \
-                                 argument and return types",
-                                region_name,
-                                self.tcx.item_path_str(fn_def_id)));
-                }
-            }
-        }
-    }
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
@@ -1104,7 +1116,7 @@ fn report_inference_failure(&self,
                 format!(" for lifetime parameter {}in trait containing associated type `{}`",
                         br_string(br), type_name)
             }
-            infer::EarlyBoundRegion(_, name) => {
+            infer::EarlyBoundRegion(_, name, _) => {
                 format!(" for lifetime parameter `{}`",
                         name)
             }
index 08e522f5fd6ee4a39599f905b1f2874c74fa6575..e919f025409c510a717458b4ea4d073c5ea83e8e 100644 (file)
@@ -622,7 +622,7 @@ pub fn skolemize_late_bound_regions<T>(&self,
     /// hold. See `README.md` for more details.
     pub fn leak_check(&self,
                       overly_polymorphic: bool,
-                      span: Span,
+                      _span: Span,
                       skol_map: &SkolemizationMap<'tcx>,
                       snapshot: &CombinedSnapshot)
                       -> RelateResult<'tcx, ()>
@@ -630,43 +630,6 @@ pub fn leak_check(&self,
         debug!("leak_check: skol_map={:?}",
                skol_map);
 
-        // ## Issue #32330 warnings
-        //
-        // When Issue #32330 is fixed, a certain number of late-bound
-        // regions (LBR) will become early-bound. We wish to issue
-        // warnings when the result of `leak_check` relies on such LBR, as
-        // that means that compilation will likely start to fail.
-        //
-        // Recall that when we do a "HR subtype" check, we replace all
-        // late-bound regions (LBR) in the subtype with fresh variables,
-        // and skolemize the late-bound regions in the supertype. If those
-        // skolemized regions from the supertype wind up being
-        // super-regions (directly or indirectly) of either
-        //
-        // - another skolemized region; or,
-        // - some region that pre-exists the HR subtype check
-        //   - e.g., a region variable that is not one of those created
-        //     to represent bound regions in the subtype
-        //
-        // then leak-check (and hence the subtype check) fails.
-        //
-        // What will change when we fix #32330 is that some of the LBR in the
-        // subtype may become early-bound. In that case, they would no longer be in
-        // the "permitted set" of variables that can be related to a skolemized
-        // type.
-        //
-        // So the foundation for this warning is to collect variables that we found
-        // to be related to a skolemized type. For each of them, we have a
-        // `BoundRegion` which carries a `Issue32330` flag. We check whether any of
-        // those flags indicate that this variable was created from a lifetime
-        // that will change from late- to early-bound. If so, we issue a warning
-        // indicating that the results of compilation may change.
-        //
-        // This is imperfect, since there are other kinds of code that will not
-        // compile once #32330 is fixed. However, it fixes the errors observed in
-        // practice on crater runs.
-        let mut warnings = vec![];
-
         let new_vars = self.region_vars_confined_to_snapshot(snapshot);
         for (&skol_br, &skol) in skol_map {
             // The inputs to a skolemized variable can only
@@ -680,13 +643,6 @@ pub fn leak_check(&self,
                 match *tainted_region {
                     ty::ReVar(vid) => {
                         if new_vars.contains(&vid) {
-                            warnings.extend(
-                                match self.region_vars.var_origin(vid) {
-                                    LateBoundRegion(_,
-                                                    ty::BrNamed(.., wc),
-                                                    _) => Some(wc),
-                                    _ => None,
-                                });
                             continue;
                         }
                     }
@@ -712,8 +668,6 @@ pub fn leak_check(&self,
             }
         }
 
-        self.issue_32330_warnings(span, &warnings);
-
         Ok(())
     }
 
index ef93a10808bfdcb95a6520ac7a3e7f6f2c0736ba..c3a6a62764d0b56ce327ada6900b82cb57835ee8 100644 (file)
@@ -368,7 +368,7 @@ pub enum RegionVariableOrigin {
     Coercion(Span),
 
     // Region variables created as the values for early-bound regions
-    EarlyBoundRegion(Span, ast::Name),
+    EarlyBoundRegion(Span, ast::Name, Option<ty::Issue32330>),
 
     // Region variables created for bound regions
     // in a function or method that is called
@@ -1184,7 +1184,7 @@ pub fn region_var_for_def(&self,
                               span: Span,
                               def: &ty::RegionParameterDef)
                               -> &'tcx ty::Region {
-        self.next_region_var(EarlyBoundRegion(span, def.name))
+        self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330))
     }
 
     /// Create a type inference variable for the given
@@ -1761,7 +1761,7 @@ pub fn span(&self) -> Span {
             AddrOfRegion(a) => a,
             Autoref(a) => a,
             Coercion(a) => a,
-            EarlyBoundRegion(a, _) => a,
+            EarlyBoundRegion(a, ..) => a,
             LateBoundRegion(a, ..) => a,
             BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
             UpvarRegion(_, a) => a
index 88ef2c69a04dce975ab907a9ee7b1a1e97bee033..158b406deb8a48c69323564cb2dee343a07cf2fa 100644 (file)
@@ -31,7 +31,7 @@
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
-use util::nodemap::{NodeMap, FxHashSet, FxHashMap, DefIdMap};
+use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap};
 use rustc_back::slice;
 
 use hir;
@@ -150,10 +150,14 @@ pub struct NamedRegionMap {
     // `Region` describing how that region is bound
     pub defs: NodeMap<Region>,
 
-    // the set of lifetime def ids that are late-bound; late-bound ids
-    // are named regions appearing in fn arguments that do not appear
-    // in where-clauses
-    pub late_bound: NodeMap<ty::Issue32330>,
+    // the set of lifetime def ids that are late-bound; a region can
+    // be late-bound if (a) it does NOT appear in a where-clause and
+    // (b) it DOES appear in the arguments.
+    pub late_bound: NodeSet,
+
+    // Contains the node-ids for lifetimes that were (incorrectly) categorized
+    // as late-bound, until #32330 was fixed.
+    pub issue_32330: NodeMap<ty::Issue32330>,
 
     // For each type and trait definition, maps type parameters
     // to the trait object lifetime defaults computed from them.
@@ -261,7 +265,8 @@ pub fn krate(sess: &Session,
     let krate = hir_map.krate();
     let mut map = NamedRegionMap {
         defs: NodeMap(),
-        late_bound: NodeMap(),
+        late_bound: NodeSet(),
+        issue_32330: NodeMap(),
         object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map),
     };
     sess.track_errors(|| {
@@ -840,7 +845,7 @@ fn visit_early_late<F>(&mut self,
         }
 
         let lifetimes = generics.lifetimes.iter().map(|def| {
-            if self.map.late_bound.contains_key(&def.lifetime.id) {
+            if self.map.late_bound.contains(&def.lifetime.id) {
                 Region::late(def)
             } else {
                 Region::early(&mut index, def)
@@ -1610,22 +1615,26 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
         // just mark it so we can issue warnings.
         let constrained_by_input = constrained_by_input.regions.contains(&name);
         let appears_in_output = appears_in_output.regions.contains(&name);
-        let will_change = !constrained_by_input && appears_in_output;
-        let issue_32330 = if will_change {
-            ty::Issue32330::WillChange {
-                fn_def_id: fn_def_id,
-                region_name: name,
-            }
-        } else {
-            ty::Issue32330::WontChange
-        };
+        if !constrained_by_input && appears_in_output {
+            debug!("inserting issue_32330 entry for {:?}, {:?} on {:?}",
+                   lifetime.lifetime.id,
+                   name,
+                   fn_def_id);
+            map.issue_32330.insert(
+                lifetime.lifetime.id,
+                ty::Issue32330 {
+                    fn_def_id: fn_def_id,
+                    region_name: name,
+                });
+            continue;
+        }
 
         debug!("insert_late_bound_lifetimes: \
-                lifetime {:?} with id {:?} is late-bound ({:?}",
-               lifetime.lifetime.name, lifetime.lifetime.id, issue_32330);
+                lifetime {:?} with id {:?} is late-bound",
+               lifetime.lifetime.name, lifetime.lifetime.id);
 
-        let prev = map.late_bound.insert(lifetime.lifetime.id, issue_32330);
-        assert!(prev.is_none(), "visited lifetime {:?} twice", lifetime.lifetime.id);
+        let inserted = map.late_bound.insert(lifetime.lifetime.id);
+        assert!(inserted, "visited lifetime {:?} twice", lifetime.lifetime.id);
     }
 
     return;
index c9ae3b3df028c80ddb07bf7034087ed4f0c36dc5..4d9514b1473c7a6d254f59e929ce9df7e6ca4cd5 100644 (file)
@@ -606,6 +606,7 @@ pub struct RegionParameterDef {
     pub name: Name,
     pub def_id: DefId,
     pub index: u32,
+    pub issue_32330: Option<ty::Issue32330>,
 
     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
     /// on generic parameter `'a`, asserts data of lifetime `'a`
@@ -622,8 +623,7 @@ pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
     }
 
     pub fn to_bound_region(&self) -> ty::BoundRegion {
-        // this is an early bound region, so unaffected by #32330
-        ty::BoundRegion::BrNamed(self.def_id, self.name, Issue32330::WontChange)
+        ty::BoundRegion::BrNamed(self.def_id, self.name)
     }
 }
 
index 9bba4c6e37a69dda4b77460bd6a0f5e5fd4b6d22..4ce1d7a9013621cce9c4deb186da33c39eaa1021 100644 (file)
@@ -58,7 +58,7 @@ pub enum BoundRegion {
     ///
     /// The def-id is needed to distinguish free regions in
     /// the event of shadowing.
-    BrNamed(DefId, Name, Issue32330),
+    BrNamed(DefId, Name),
 
     /// Fresh bound identifiers created during GLB computations.
     BrFresh(u32),
@@ -68,23 +68,18 @@ pub enum BoundRegion {
     BrEnv
 }
 
-/// True if this late-bound region is unconstrained, and hence will
-/// become early-bound once #32330 is fixed.
+/// When a region changed from late-bound to early-bound when #32330
+/// was fixed, its `RegionParameterDef` will have one of these
+/// structures that we can use to give nicer errors.
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash,
          RustcEncodable, RustcDecodable)]
-pub enum Issue32330 {
-    WontChange,
+pub struct Issue32330 {
+    /// fn where is region declared
+    pub fn_def_id: DefId,
 
-    /// this region will change from late-bound to early-bound once
-    /// #32330 is fixed.
-    WillChange {
-        /// fn where is region declared
-        fn_def_id: DefId,
-
-        /// name of region; duplicates the info in BrNamed but convenient
-        /// to have it here, and this code is only temporary
-        region_name: ast::Name,
-    }
+    /// name of region; duplicates the info in BrNamed but convenient
+    /// to have it here, and this code is only temporary
+    pub region_name: ast::Name,
 }
 
 // NB: If you change this, you'll probably want to change the corresponding
index 5d6ee1a277a5f88049c9d68a33dc1f462a76066a..a45c43235ebf857ff203cf6ef128360cbf10154c 100644 (file)
@@ -276,7 +276,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
     let new_value = tcx.replace_late_bound_regions(&value, |br| {
         let _ = start_or_continue(f, "for<", ", ");
         let br = match br {
-            ty::BrNamed(_, name, _) => {
+            ty::BrNamed(_, name) => {
                 let _ = write!(f, "{}", name);
                 br
             }
@@ -286,8 +286,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
                 let name = Symbol::intern("'r");
                 let _ = write!(f, "{}", name);
                 ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID),
-                            name,
-                            ty::Issue32330::WontChange)
+                            name)
             }
         };
         tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
@@ -435,7 +434,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
 
         match *self {
-            BrNamed(_, name, _) => write!(f, "{}", name),
+            BrNamed(_, name) => write!(f, "{}", name),
             BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
         }
     }
@@ -446,9 +445,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             BrAnon(n) => write!(f, "BrAnon({:?})", n),
             BrFresh(n) => write!(f, "BrFresh({:?})", n),
-            BrNamed(did, name, issue32330) => {
-                write!(f, "BrNamed({:?}:{:?}, {:?}, {:?})",
-                       did.krate, did.index, name, issue32330)
+            BrNamed(did, name) => {
+                write!(f, "BrNamed({:?}:{:?}, {:?})",
+                       did.krate, did.index, name)
             }
             BrEnv => "BrEnv".fmt(f),
         }
index a3373f6da28526b17e2ae4f1bc65777404ad689e..fb6d28448a0c5524cbaf6e78c0a1d0d1656c46fd 100644 (file)
@@ -29,7 +29,6 @@
 use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
-use rustc::lint;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
@@ -148,20 +147,9 @@ pub fn ast_region_to_region(&self,
             }
 
             Some(&rl::Region::LateBound(debruijn, id)) => {
-                // If this region is declared on a function, it will have
-                // an entry in `late_bound`, but if it comes from
-                // `for<'a>` in some type or something, it won't
-                // necessarily have one. In that case though, we won't be
-                // changed from late to early bound, so we can just
-                // substitute false.
-                let issue_32330 = tcx.named_region_map
-                                     .late_bound
-                                     .get(&id)
-                                     .cloned()
-                                     .unwrap_or(ty::Issue32330::WontChange);
                 let name = tcx.hir.name(id);
                 tcx.mk_region(ty::ReLateBound(debruijn,
-                    ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330)))
+                    ty::BrNamed(tcx.hir.local_def_id(id), name)))
             }
 
             Some(&rl::Region::LateBoundAnon(debruijn, index)) => {
@@ -177,17 +165,10 @@ pub fn ast_region_to_region(&self,
             }
 
             Some(&rl::Region::Free(scope, id)) => {
-                // As in Region::LateBound above, could be missing for some late-bound
-                // regions, but also for early-bound regions.
-                let issue_32330 = tcx.named_region_map
-                                     .late_bound
-                                     .get(&id)
-                                     .cloned()
-                                     .unwrap_or(ty::Issue32330::WontChange);
                 let name = tcx.hir.name(id);
                 tcx.mk_region(ty::ReFree(ty::FreeRegion {
                     scope: scope.to_code_extent(&tcx.region_maps),
-                    bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330)
+                    bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name)
                 }))
 
                     // (*) -- not late-bound, won't change
@@ -566,7 +547,7 @@ fn trait_defines_associated_type_named(&self,
 
     fn ast_type_binding_to_poly_projection_predicate(
         &self,
-        path_id: ast::NodeId,
+        _path_id: ast::NodeId,
         trait_ref: ty::PolyTraitRef<'tcx>,
         binding: &ConvertedBinding<'tcx>)
         -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
@@ -602,7 +583,7 @@ fn ast_type_binding_to_poly_projection_predicate(
         debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
         for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
             let br_name = match *br {
-                ty::BrNamed(_, name, _) => name,
+                ty::BrNamed(_, name) => name,
                 _ => {
                     span_bug!(
                         binding.span,
@@ -610,13 +591,13 @@ fn ast_type_binding_to_poly_projection_predicate(
                         br);
                 }
             };
-            tcx.sess.add_lint(
-                lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
-                path_id,
-                binding.span,
-                format!("binding for associated type `{}` references lifetime `{}`, \
-                         which does not appear in the trait input types",
-                        binding.item_name, br_name));
+            struct_span_err!(tcx.sess,
+                             binding.span,
+                             E0582,
+                             "binding for associated type `{}` references lifetime `{}`, \
+                              which does not appear in the trait input types",
+                             binding.item_name, br_name)
+                .emit();
         }
 
         // Simple case: X is defined in the current trait.
@@ -1197,7 +1178,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
                 for br in late_bound_in_ret.difference(&late_bound_in_args) {
                     let br_name = match *br {
-                        ty::BrNamed(_, name, _) => name,
+                        ty::BrNamed(_, name) => name,
                         _ => {
                             span_bug!(
                                 bf.decl.output.span(),
@@ -1205,13 +1186,13 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
                                 br);
                         }
                     };
-                    tcx.sess.add_lint(
-                        lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
-                        ast_ty.id,
-                        ast_ty.span,
-                        format!("return type references lifetime `{}`, \
-                                 which does not appear in the trait input types",
-                                br_name));
+                    struct_span_err!(tcx.sess,
+                                     ast_ty.span,
+                                     E0581,
+                                     "return type references lifetime `{}`, \
+                                      which does not appear in the fn input types",
+                                     br_name)
+                        .emit();
                 }
                 tcx.mk_fn_ptr(bare_fn_ty)
             }
index c4a366c2f17fe1ed336ac4bab56cd6c31a68551e..8329d3eeed9e54c628164ee1ff99fa22c0944eab 100644 (file)
@@ -1418,7 +1418,7 @@ fn get_type_parameter_bounds(&self,
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
                 -> Option<&'tcx ty::Region> {
         let v = match def {
-            Some(def) => infer::EarlyBoundRegion(span, def.name),
+            Some(def) => infer::EarlyBoundRegion(span, def.name, def.issue_32330),
             None => infer::MiscVariable(span)
         };
         Some(self.next_region_var(v))
index 9df0542f51fa109240d4ba1141e50f0c148faeb1..28156dd616b3a59da3e615ef9437526e4b7a657e 100644 (file)
@@ -108,7 +108,7 @@ fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
             };
             match *r {
                 ty::ReFree(ty::FreeRegion {
-                    bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
+                    bound_region: ty::BoundRegion::BrNamed(def_id, name), ..
                 }) => {
                     let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
                         index: i as u32,
index 266975994ec3ae01d9061cd2291d71e76b431ff8..1981e7c3a3d122086fcd695912cb515782cd2a6d 100644 (file)
@@ -1442,11 +1442,15 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
         let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
+            let issue_32330 = ccx.tcx.named_region_map.issue_32330
+                                                      .get(&l.lifetime.id)
+                                                      .cloned();
             ty::RegionParameterDef {
                 name: l.lifetime.name,
                 index: own_start + i as u32,
                 def_id: tcx.hir.local_def_id(l.lifetime.id),
                 pure_wrt_drop: l.pure_wrt_drop,
+                issue_32330: issue_32330,
             }
         }).collect::<Vec<_>>();
 
@@ -1675,7 +1679,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
     ast_generics
         .lifetimes
         .iter()
-        .filter(|l| !ccx.tcx.named_region_map.late_bound.contains_key(&l.lifetime.id))
+        .filter(|l| !ccx.tcx.named_region_map.late_bound.contains(&l.lifetime.id))
         .collect()
 }
 
index c41d40b41e42ab53c8a9ca53a780e1766a8bfc82..5bfc3a934af059ee7999a5904a8eb862f497a75a 100644 (file)
@@ -4056,6 +4056,74 @@ fn main() {
 ```
 "##,
 
+E0581: r##"
+In a `fn` type, a lifetime appears only in the return type,
+and not in the arguments types.
+
+Erroneous code example:
+
+```compile_fail,E0581
+fn main() {
+    // Here, `'a` appears only in the return type:
+    let x: for<'a> fn() -> &'a i32;
+}
+```
+
+To fix this issue, either use the lifetime in the arguments, or use
+`'static`. Example:
+
+```
+fn main() {
+    // Here, `'a` appears only in the return type:
+    let x: for<'a> fn(&'a i32) -> &'a i32;
+    let y: fn() -> &'static i32;
+}
+```
+
+Note: The examples above used to be (erroneously) accepted by the
+compiler, but this was since corrected. See [issue #33685] for more
+details.
+
+[issue #33685]: https://github.com/rust-lang/rust/issues/33685
+"##,
+
+    E0582: r##"
+A lifetime appears only in an associated-type binding,
+and not in the input types to the trait.
+
+Erroneous code example:
+
+```compile_fail,E0582
+fn bar<F>(t: F)
+    // No type can satisfy this requirement, since `'a` does not
+    // appear in any of the input types (here, `i32`):
+    where F: for<'a> Fn(i32) -> Option<&'a i32>
+{
+}
+
+fn main() { }
+```
+
+To fix this issue, either use the lifetime in the inputs, or use
+`'static`. Example:
+
+```
+fn bar<F, G>(t: F, u: G)
+    where F: for<'a> Fn(&'a i32) -> Option<&'a i32>,
+          G: Fn(i32) -> Option<&'static i32>,
+{
+}
+
+fn main() { }
+```
+
+Note: The examples above used to be (erroneously) accepted by the
+compiler, but this was since corrected. See [issue #33685] for more
+details.
+
+[issue #33685]: https://github.com/rust-lang/rust/issues/33685
+"##,
+
 }
 
 register_diagnostics! {
index dc2aa1f138d62d04eb74b385b1875aa9feb02c75..291fc8dfa96806b43d68a9739392e4b03c053b27 100644 (file)
@@ -810,7 +810,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
     fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
-            ty::ReLateBound(_, ty::BrNamed(_, name, _)) => Some(Lifetime(name.to_string())),
+            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
             ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
 
             ty::ReLateBound(..) |
diff --git a/src/test/compile-fail/E0582.rs b/src/test/compile-fail/E0582.rs
new file mode 100644 (file)
index 0000000..5e6f65a
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 <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.
+
+// This test was derived from the wasm and parsell crates.  They
+// stopped compiling when #32330 is fixed.
+
+#![allow(dead_code, unused_variables)]
+
+use std::str::Chars;
+
+pub trait HasOutput<Ch, Str> {
+    type Output;
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)]
+pub enum Token<'a> {
+    Begin(&'a str)
+}
+
+fn mk_unexpected_char_err<'a>() -> Option<&'a i32> {
+    unimplemented!()
+}
+
+fn foo<'a>(data: &mut Chars<'a>) {
+    bar(mk_unexpected_char_err)
+}
+
+fn bar<F>(t: F)
+    // No type can satisfy this requirement, since `'a` does not
+    // appear in any of the input types:
+    where F: for<'a> Fn() -> Option<&'a i32>
+    //~^ ERROR E0582
+{
+}
+
+fn baz<F>(t: F)
+    // No type can satisfy this requirement, since `'a` does not
+    // appear in any of the input types:
+    where F: for<'a> Iterator<Item=&'a i32>
+    //~^ ERROR E0582
+{
+}
+
+fn main() {
+}
index de6ce798d63542c3d7431f2e182467e538c8144b..7d04372088b76f81ef2863101b6377c34cdec87e 100644 (file)
@@ -12,7 +12,7 @@
 
 #![allow(dead_code)]
 #![feature(rustc_attrs)]
-#![deny(hr_lifetime_in_assoc_type)]
+#![allow(hr_lifetime_in_assoc_type)]
 
 trait Foo<'a> {
     type Item;
@@ -25,40 +25,34 @@ impl<'a> Foo<'a> for() {
 // Check that appearing in a projection input in the argument is not enough:
 #[cfg(func)]
 fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) {
-    //[func]~^ ERROR return type references lifetime `'a`
-    //[func]~| WARNING previously accepted
+    //[func]~^ ERROR E0581
 }
 
 // Check that appearing in a projection input in the return still
 // causes an error:
 #[cfg(func)]
 fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) {
-    //[func]~^ ERROR return type references lifetime `'a`
-    //[func]~| WARNING previously accepted
+    //[func]~^ ERROR E0581
 }
 
 #[cfg(object)]
 fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) {
-    //[object]~^ ERROR `Output` references lifetime `'a`
-    //[object]~| WARNING previously accepted
+    //[object]~^ ERROR E0582
 }
 
 #[cfg(object)]
 fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) {
-    //[object]~^ ERROR `Output` references lifetime `'a`
-    //[object]~| WARNING previously accepted
+    //[object]~^ ERROR E0582
 }
 
 #[cfg(clause)]
 fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 {
     //[clause]~^ ERROR `Output` references lifetime `'a`
-    //[clause]~| WARNING previously accepted
 }
 
 #[cfg(clause)]
 fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
     //[clause]~^ ERROR `Output` references lifetime `'a`
-    //[clause]~| WARNING previously accepted
 }
 
 #[rustc_error]
index 020c9e5e1db5999280df72fbdb813ba9f62e57b2..7cb0623315e1e41ea2fef29da529514f57d8e213 100644 (file)
@@ -13,7 +13,6 @@
 #![allow(dead_code)]
 #![feature(rustc_attrs)]
 #![feature(unboxed_closures)]
-#![deny(hr_lifetime_in_assoc_type)]
 
 trait Foo {
     type Item;
@@ -22,49 +21,41 @@ trait Foo {
 #[cfg(angle)]
 fn angle<T: for<'a> Foo<Item=&'a i32>>() {
     //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
-    //[angle]~| WARNING previously accepted
 }
 
 #[cfg(angle)]
 fn angle1<T>() where T: for<'a> Foo<Item=&'a i32> {
     //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
-    //[angle]~| WARNING previously accepted
 }
 
 #[cfg(angle)]
 fn angle2<T>() where for<'a> T: Foo<Item=&'a i32> {
     //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
-    //[angle]~| WARNING previously accepted
 }
 
 #[cfg(angle)]
 fn angle3(_: &for<'a> Foo<Item=&'a i32>) {
     //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
-    //[angle]~| WARNING previously accepted
 }
 
 #[cfg(paren)]
 fn paren<T: for<'a> Fn() -> &'a i32>() {
     //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
-    //[paren]~| WARNING previously accepted
 }
 
 #[cfg(paren)]
 fn paren1<T>() where T: for<'a> Fn() -> &'a i32 {
     //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
-    //[paren]~| WARNING previously accepted
 }
 
 #[cfg(paren)]
 fn paren2<T>() where for<'a> T: Fn() -> &'a i32 {
     //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
-    //[paren]~| WARNING previously accepted
 }
 
 #[cfg(paren)]
 fn paren3(_: &for<'a> Fn() -> &'a i32) {
     //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
-    //[paren]~| WARNING previously accepted
 }
 
 #[cfg(elision)]
index 0b4a9bf58a66c6af56abd9043d0c084eba46aadf..7c1fbfa53d9651b997c5aa21ed56082a92677ec6 100644 (file)
@@ -22,27 +22,23 @@ trait Foo {
 #[cfg(sig)]
 fn sig1(_: for<'a> fn() -> &'a i32) {
     //[sig]~^ ERROR return type references lifetime `'a`
-    //[sig]~| WARNING previously accepted
 }
 
 #[cfg(sig)]
 fn sig2(_: for<'a, 'b> fn(&'b i32) -> &'a i32) {
     //[sig]~^ ERROR return type references lifetime `'a`
-    //[sig]~| WARNING previously accepted
 }
 
 #[cfg(local)]
 fn local1() {
     let _: for<'a> fn() -> &'a i32 = loop { };
     //[local]~^ ERROR return type references lifetime `'a`
-    //[local]~| WARNING previously accepted
 }
 
 #[cfg(structure)]
 struct Struct1 {
     x: for<'a> fn() -> &'a i32
     //[structure]~^ ERROR return type references lifetime `'a`
-    //[structure]~| WARNING previously accepted
 }
 
 #[cfg(elision)]
diff --git a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs
deleted file mode 100644 (file)
index 6ba09ac..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 <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.
-
-// This test was derived from the wasm and parsell crates.  They
-// stopped compiling when #32330 is fixed.
-
-#![allow(dead_code, unused_variables)]
-#![deny(hr_lifetime_in_assoc_type)]
-
-use std::str::Chars;
-
-pub trait HasOutput<Ch, Str> {
-    type Output;
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)]
-pub enum Token<'a> {
-    Begin(&'a str)
-}
-
-fn mk_unexpected_char_err<'a>() -> Option<&'a i32> {
-    unimplemented!()
-}
-
-fn foo<'a>(data: &mut Chars<'a>) {
-    bar(mk_unexpected_char_err)
-    //~^ ERROR lifetime parameter `'a` declared on fn `mk_unexpected_char_err`
-    //~| WARNING hard error in a future release
-}
-
-fn bar<F>(t: F)
-    // No type can satisfy this requirement, since `'a` does not
-    // appear in any of the input types:
-    where F: for<'a> Fn() -> Option<&'a i32>
-    //~^ ERROR associated type `Output` references lifetime `'a`, which does not
-    //~| WARNING hard error in a future release
-{
-}
-
-fn main() {
-}
index c0116b21166e0350429cc6063306b82bf5b22fac..ac7dd022c7c467ab287f989c7850b361e4888a0a 100644 (file)
@@ -46,7 +46,10 @@ fn baz(x: &S) -> &S {
 
 fn supply_F() {
     want_F(foo);
-    want_F(bar);
+
+    // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly
+    want_F(bar); //~ ERROR E0308
+
     want_F(baz);
 }
 
diff --git a/src/test/ui/regions-fn-subtyping-return-static.rs b/src/test/ui/regions-fn-subtyping-return-static.rs
new file mode 100644 (file)
index 0000000..9098511
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2012 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.
+
+// In this fn, the type `F` is a function that takes a reference to a
+// struct and returns another reference with the same lifetime.
+//
+// Meanwhile, the bare fn `foo` takes a reference to a struct with
+// *ANY* lifetime and returns a reference with the 'static lifetime.
+// This can safely be considered to be an instance of `F` because all
+// lifetimes are sublifetimes of 'static.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct S;
+
+// Given 'cx, return 'cx
+type F = for<'cx> fn(&'cx S) -> &'cx S;
+fn want_F(f: F) { }
+
+// Given anything, return 'static
+type G = for<'cx> fn(&'cx S) -> &'static S;
+fn want_G(f: G) { }
+
+// Should meet both.
+fn foo(x: &S) -> &'static S {
+    panic!()
+}
+
+// Should meet both.
+fn bar<'a,'b>(x: &'a S) -> &'b S {
+    panic!()
+}
+
+// Meets F, but not G.
+fn baz(x: &S) -> &S {
+    panic!()
+}
+
+fn supply_F() {
+    want_F(foo);
+
+    // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly
+    want_F(bar); //~ ERROR E0308
+
+    want_F(baz);
+}
+
+pub fn main() {
+}
diff --git a/src/test/ui/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions-fn-subtyping-return-static.stderr
new file mode 100644 (file)
index 0000000..0c7b44a
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static.rs:51:12
+   |
+51 |     want_F(bar); //~ ERROR E0308
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |
+   = note: expected type `fn(&'cx S) -> &'cx S`
+              found type `fn(&'a S) -> &S {bar::<'_>}`
+   = note: lifetime parameter `'b` declared on fn `bar` appears only in the return type, but here is required to be higher-ranked, which means that `'b` must appear in both argument and return types
+   = note: this error is the result of a recent bug fix; for more information, see issue #33685 <https://github.com/rust-lang/rust/issues/33685>
+
+error: aborting due to previous error
+