From 2f3eab2f4b3acd0a05d1fd22fa6a0295ae9abcd6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 4 Dec 2014 20:06:41 -0500 Subject: [PATCH] Fix two bugs in HRTB: 1. Categorize early-vs-late bindings on impls when constructing generics, so that we don't add unnecessary region parameters. 2. Correct the DeBruijn indices when substituting the self type into the method signature. Previously, the DeBruijn index for the self type was not being adjusted to account for the fn binder. This mean that when late-bound regions were instantiated, you sometimes wind up with two distinct lifetimes. Fixes #19537. --- src/librustc/middle/typeck/astconv.rs | 17 +++++++---- src/librustc/middle/typeck/collect.rs | 20 ++++++++++++- .../compile-fail/hrtb-debruijn-in-receiver.rs | 28 +++++++++++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/hrtb-debruijn-in-receiver.rs diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 89c004fc64596..3c71b3e80cf31 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -52,6 +52,7 @@ use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty::{mod, Ty}; +use middle::ty_fold; use middle::typeck::lookup_def_tcx; use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; @@ -1069,7 +1070,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( opt_self_info: Option>, decl: &ast::FnDecl) -> (ty::BareFnTy<'tcx>, - Option) { + Option) +{ debug!("ty_of_method_or_bare_fn"); // New region names that appear inside of the arguments of the function @@ -1085,6 +1087,11 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( let (self_ty, mut implied_output_region) = match opt_self_info { None => (None, None), Some(self_info) => { + // Shift regions in the self type by 1 to account for the binding + // level introduced by the function itself. + let untransformed_self_ty = + ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty); + // Figure out and record the explicit self category. let explicit_self_category = determine_explicit_self_category(this, &rb, &self_info); @@ -1094,21 +1101,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (None, None) } ty::ByValueExplicitSelfCategory => { - (Some(self_info.untransformed_self_ty), None) + (Some(untransformed_self_ty), None) } ty::ByReferenceExplicitSelfCategory(region, mutability) => { (Some(ty::mk_rptr(this.tcx(), region, ty::mt { - ty: self_info.untransformed_self_ty, + ty: untransformed_self_ty, mutbl: mutability })), Some(region)) } ty::ByBoxExplicitSelfCategory => { - (Some(ty::mk_uniq(this.tcx(), - self_info.untransformed_self_ty)), - None) + (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None) } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 3a62978ed007a..09456fc8999c7 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1074,7 +1074,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_impl( ccx, generics, CreateTypeParametersForAssociatedTypes); @@ -1676,6 +1676,24 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics } +fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ast::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics<'tcx> +{ + let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); + debug!("ty_generics_for_impl: early_lifetimes={}", + early_lifetimes); + ty_generics(ccx, + subst::TypeSpace, + early_lifetimes.as_slice(), + generics.ty_params.as_slice(), + ty::Generics::empty(), + &generics.where_clause, + create_type_parameters_for_associated_types) +} + fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, diff --git a/src/test/compile-fail/hrtb-debruijn-in-receiver.rs b/src/test/compile-fail/hrtb-debruijn-in-receiver.rs new file mode 100644 index 0000000000000..2dbd16107b0d5 --- /dev/null +++ b/src/test/compile-fail/hrtb-debruijn-in-receiver.rs @@ -0,0 +1,28 @@ +// 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. + +// Test the case where the `Self` type has a bound lifetime that must +// be adjusted in the fn signature. Issue #19537. + +use std::collections::HashMap; + +struct Foo<'a> { + map: HashMap +} + +impl<'a> Foo<'a> { + fn new() -> Foo<'a> { panic!() } + fn insert(&'a mut self) { } +} +fn main() { + let mut foo = Foo::new(); + foo.insert(); + foo.insert(); //~ ERROR cannot borrow +}