Skip to content

Commit

Permalink
Fix two bugs in HRTB: 1. Categorize early-vs-late bindings on impls w…
Browse files Browse the repository at this point in the history
…hen 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 rust-lang#19537.
  • Loading branch information
nikomatsakis committed Dec 5, 2014
1 parent 82fc1aa commit 2f3eab2
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
17 changes: 11 additions & 6 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1069,7 +1070,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
opt_self_info: Option<SelfInfo<'a, 'tcx>>,
decl: &ast::FnDecl)
-> (ty::BareFnTy<'tcx>,
Option<ty::ExplicitSelfCategory>) {
Option<ty::ExplicitSelfCategory>)
{
debug!("ty_of_method_or_bare_fn");

// New region names that appear inside of the arguments of the function
Expand All @@ -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);
Expand All @@ -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)
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/librustc/middle/typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
28 changes: 28 additions & 0 deletions src/test/compile-fail/hrtb-debruijn-in-receiver.rs
Original file line number Diff line number Diff line change
@@ -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 <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.

// 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<uint, &'a str>
}

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
}

0 comments on commit 2f3eab2

Please sign in to comment.