Skip to content

Commit cbfd88a

Browse files
committed
Update region inference for traits so that a method with
explicit self doesn't incorrectly cause the entire trait to be tagged as being region-parameterized. Fixes rust-lang#5224.
1 parent 65986ba commit cbfd88a

File tree

13 files changed

+263
-189
lines changed

13 files changed

+263
-189
lines changed

src/librustc/middle/check_const.rs

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use middle::ty;
1616
use middle::typeck;
1717
use util::ppaux;
1818

19-
use core::option;
2019
use syntax::ast::*;
2120
use syntax::codemap;
2221
use syntax::{visit, ast_util, ast_map};

src/librustc/middle/check_match.rs

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use middle::typeck::method_map;
1919
use middle::moves;
2020
use util::ppaux::ty_to_str;
2121

22-
use core::option;
2322
use core::uint;
2423
use core::vec;
2524
use std::sort;

src/librustc/middle/kind.rs

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use middle::ty;
1818
use middle::typeck;
1919
use util::ppaux::{ty_to_str, tys_to_str};
2020

21-
use core::option;
2221
use core::str;
2322
use core::vec;
2423
use std::oldmap::HashMap;

src/librustc/middle/region.rs

+50-29
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,13 @@ pub struct DetermineRpCtxt {
416416
item_id: ast::node_id,
417417

418418
// true when we are within an item but not within a method.
419-
// see long discussion on region_is_relevant()
419+
// see long discussion on region_is_relevant().
420420
anon_implies_rp: bool,
421421

422+
// true when we are not within an &self method.
423+
// see long discussion on region_is_relevant().
424+
self_implies_rp: bool,
425+
422426
// encodes the context of the current type; invariant if
423427
// mutable, covariant otherwise
424428
ambient_variance: region_variance,
@@ -458,14 +462,14 @@ pub fn add_variance(+ambient_variance: region_variance,
458462
}
459463

460464
pub impl DetermineRpCtxt {
461-
fn add_variance(@mut self, variance: region_variance) -> region_variance {
465+
fn add_variance(&self, variance: region_variance) -> region_variance {
462466
add_variance(self.ambient_variance, variance)
463467
}
464468

465469
/// Records that item `id` is region-parameterized with the
466470
/// variance `variance`. If `id` was already parameterized, then
467471
/// the new variance is joined with the old variance.
468-
fn add_rp(@mut self, id: ast::node_id, variance: region_variance) {
472+
fn add_rp(&mut self, id: ast::node_id, variance: region_variance) {
469473
assert id != 0;
470474
let old_variance = self.region_paramd_items.find(&id);
471475
let joined_variance = match old_variance {
@@ -490,7 +494,7 @@ pub impl DetermineRpCtxt {
490494
/// `from`. Put another way, it indicates that the current item
491495
/// contains a value of type `from`, so if `from` is
492496
/// region-parameterized, so is the current item.
493-
fn add_dep(@mut self, from: ast::node_id) {
497+
fn add_dep(&mut self, from: ast::node_id) {
494498
debug!("add dependency from %d -> %d (%s -> %s) with variance %?",
495499
from, self.item_id,
496500
ast_map::node_id_to_str(self.ast_map, from,
@@ -515,42 +519,46 @@ pub impl DetermineRpCtxt {
515519
}
516520

517521
// Determines whether a reference to a region that appears in the
518-
// AST implies that the enclosing type is region-parameterized.
519-
//
520-
// This point is subtle. Here are four examples to make it more
522+
// AST implies that the enclosing type is region-parameterized (RP).
523+
// This point is subtle. Here are some examples to make it more
521524
// concrete.
522525
//
523526
// 1. impl foo for &int { ... }
524527
// 2. impl foo for &self/int { ... }
525-
// 3. impl foo for bar { fn m() -> &self/int { ... } }
526-
// 4. impl foo for bar { fn m() -> &int { ... } }
528+
// 3. impl foo for bar { fn m(@self) -> &self/int { ... } }
529+
// 4. impl foo for bar { fn m(&self) -> &self/int { ... } }
530+
// 5. impl foo for bar { fn m(&self) -> &int { ... } }
527531
//
528532
// In case 1, the anonymous region is being referenced,
529533
// but it appears in a context where the anonymous region
530-
// resolves to self, so the impl foo is region-parameterized.
534+
// resolves to self, so the impl foo is RP.
531535
//
532536
// In case 2, the self parameter is written explicitly.
533537
//
534-
// In case 3, the method refers to self, so that implies that the
535-
// impl must be region parameterized. (If the type bar is not
536-
// region parameterized, that is an error, because the self region
537-
// is effectively unconstrained, but that is detected elsewhere).
538+
// In case 3, the method refers to the region `self`, so that
539+
// implies that the impl must be region parameterized. (If the
540+
// type bar is not region parameterized, that is an error, because
541+
// the self region is effectively unconstrained, but that is
542+
// detected elsewhere).
543+
//
544+
// In case 4, the method refers to the region `self`, but the
545+
// `self` region is bound by the `&self` receiver, and so this
546+
// does not require that `bar` be RP.
538547
//
539-
// In case 4, the anonymous region is referenced, but it
548+
// In case 5, the anonymous region is referenced, but it
540549
// bound by the method, so it does not refer to self. This impl
541550
// need not be region parameterized.
542551
//
543-
// So the rules basically are: the `self` region always implies
544-
// that the enclosing type is region parameterized. The anonymous
545-
// region also does, unless it appears within a method, in which
546-
// case it is bound. We handle this by setting a flag
547-
// (anon_implies_rp) to true when we enter an item and setting
548-
// that flag to false when we enter a method.
549-
fn region_is_relevant(@mut self, r: @ast::region) -> bool {
552+
// Normally, & or &self implies that the enclosing item is RP.
553+
// However, within a function, & is always bound. Within a method
554+
// with &self type, &self is also bound. We detect those last two
555+
// cases via flags (anon_implies_rp and self_implies_rp) that are
556+
// true when the anon or self region implies RP.
557+
fn region_is_relevant(&self, r: @ast::region) -> bool {
550558
match r.node {
551559
ast::re_static => false,
552560
ast::re_anon => self.anon_implies_rp,
553-
ast::re_self => true,
561+
ast::re_self => self.self_implies_rp,
554562
ast::re_named(_) => false
555563
}
556564
}
@@ -561,7 +569,7 @@ pub impl DetermineRpCtxt {
561569
//
562570
// If the region is explicitly specified, then we follows the
563571
// normal rules.
564-
fn opt_region_is_relevant(@mut self,
572+
fn opt_region_is_relevant(&self,
565573
opt_r: Option<@ast::region>)
566574
-> bool {
567575
debug!("opt_region_is_relevant: %? (anon_implies_rp=%b)",
@@ -575,16 +583,23 @@ pub impl DetermineRpCtxt {
575583
fn with(@mut self,
576584
item_id: ast::node_id,
577585
anon_implies_rp: bool,
586+
self_implies_rp: bool,
578587
f: &fn()) {
579588
let old_item_id = self.item_id;
580589
let old_anon_implies_rp = self.anon_implies_rp;
590+
let old_self_implies_rp = self.self_implies_rp;
581591
self.item_id = item_id;
582592
self.anon_implies_rp = anon_implies_rp;
583-
debug!("with_item_id(%d, %b)", item_id, anon_implies_rp);
593+
self.self_implies_rp = self_implies_rp;
594+
debug!("with_item_id(%d, %b, %b)",
595+
item_id,
596+
anon_implies_rp,
597+
self_implies_rp);
584598
let _i = ::util::common::indenter();
585599
f();
586600
self.item_id = old_item_id;
587601
self.anon_implies_rp = old_anon_implies_rp;
602+
self.self_implies_rp = old_self_implies_rp;
588603
}
589604

590605
fn with_ambient_variance(@mut self, variance: region_variance, f: &fn()) {
@@ -598,7 +613,7 @@ pub impl DetermineRpCtxt {
598613
pub fn determine_rp_in_item(item: @ast::item,
599614
&&cx: @mut DetermineRpCtxt,
600615
visitor: visit::vt<@mut DetermineRpCtxt>) {
601-
do cx.with(item.id, true) {
616+
do cx.with(item.id, true, true) {
602617
visit::visit_item(item, cx, visitor);
603618
}
604619
}
@@ -610,7 +625,12 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
610625
_: ast::node_id,
611626
&&cx: @mut DetermineRpCtxt,
612627
visitor: visit::vt<@mut DetermineRpCtxt>) {
613-
do cx.with(cx.item_id, false) {
628+
let self_implies_rp = match fk {
629+
&visit::fk_method(_, _, m) => !m.self_ty.node.is_borrowed(),
630+
_ => true
631+
};
632+
633+
do cx.with(cx.item_id, false, self_implies_rp) {
614634
do cx.with_ambient_variance(rv_contravariant) {
615635
for decl.inputs.each |a| {
616636
(visitor.visit_ty)(a.ty, cx, visitor);
@@ -626,7 +646,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
626646
pub fn determine_rp_in_ty_method(ty_m: &ast::ty_method,
627647
&&cx: @mut DetermineRpCtxt,
628648
visitor: visit::vt<@mut DetermineRpCtxt>) {
629-
do cx.with(cx.item_id, false) {
649+
do cx.with(cx.item_id, false, !ty_m.self_ty.node.is_borrowed()) {
630650
visit::visit_ty_method(ty_m, cx, visitor);
631651
}
632652
}
@@ -735,7 +755,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
735755
ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
736756
// fn() binds the & region, so do not consider &T types that
737757
// appear *inside* a fn() type to affect the enclosing item:
738-
do cx.with(cx.item_id, false) {
758+
do cx.with(cx.item_id, false, true) {
739759
// parameters are contravariant
740760
do cx.with_ambient_variance(rv_contravariant) {
741761
for decl.inputs.each |a| {
@@ -796,6 +816,7 @@ pub fn determine_rp_in_crate(sess: Session,
796816
worklist: ~[],
797817
item_id: 0,
798818
anon_implies_rp: false,
819+
self_implies_rp: true,
799820
ambient_variance: rv_covariant
800821
};
801822

src/librustc/middle/trans/base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ use core::hash;
6969
use core::int;
7070
use core::io;
7171
use core::libc::{c_uint, c_ulonglong};
72-
use core::option;
7372
use core::uint;
7473
use std::oldmap::HashMap;
7574
use std::{oldmap, time, list};

src/librustc/middle/typeck/astconv.rs

+27-27
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,11 @@ use syntax::print::pprust::path_to_str;
6969
use util::common::indenter;
7070

7171
pub trait AstConv {
72-
fn tcx(@mut self) -> ty::ctxt;
73-
fn ccx(@mut self) -> @mut CrateCtxt;
74-
fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
72+
fn tcx(&self) -> ty::ctxt;
73+
fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
7574

7675
// what type should we use when a type is omitted?
77-
fn ty_infer(@mut self, span: span) -> ty::t;
76+
fn ty_infer(&self, span: span) -> ty::t;
7877
}
7978

8079
pub fn get_region_reporting_err(tcx: ty::ctxt,
@@ -92,8 +91,8 @@ pub fn get_region_reporting_err(tcx: ty::ctxt,
9291
}
9392

9493
pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
95-
self: @mut AC,
96-
rscope: RS,
94+
self: &AC,
95+
rscope: &RS,
9796
span: span,
9897
a_r: @ast::region)
9998
-> ty::Region {
@@ -108,8 +107,8 @@ pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
108107
}
109108

110109
pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
111-
self: @mut AC,
112-
rscope: RS,
110+
self: &AC,
111+
rscope: &RS,
113112
did: ast::def_id,
114113
path: @ast::path)
115114
-> ty_param_substs_and_ty {
@@ -164,8 +163,8 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
164163
}
165164

166165
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
167-
self: @mut AC,
168-
rscope: RS,
166+
self: &AC,
167+
rscope: &RS,
169168
did: ast::def_id,
170169
path: @ast::path,
171170
path_id: ast::node_id)
@@ -189,11 +188,11 @@ pub const NO_TPS: uint = 2;
189188
// Parses the programmer's textual representation of a type into our
190189
// internal notion of a type. `getter` is a function that returns the type
191190
// corresponding to a definition ID:
192-
pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
193-
self: @mut AC, rscope: RS, &&ast_ty: @ast::Ty) -> ty::t {
191+
pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
192+
self: &AC, rscope: &RS, &&ast_ty: @ast::Ty) -> ty::t {
194193

195-
fn ast_mt_to_mt<AC:AstConv,RS:region_scope + Copy + Durable>(
196-
self: @mut AC, rscope: RS, mt: ast::mt) -> ty::mt {
194+
fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Copy + Durable>(
195+
self: &AC, rscope: &RS, mt: ast::mt) -> ty::mt {
197196

198197
ty::mt {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl}
199198
}
@@ -202,8 +201,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
202201
// If a_seq_ty is a str or a vec, make it an estr/evec.
203202
// Also handle function sigils and first-class trait types.
204203
fn mk_pointer<AC:AstConv,RS:region_scope + Copy + Durable>(
205-
self: @mut AC,
206-
rscope: RS,
204+
self: &AC,
205+
rscope: &RS,
207206
a_seq_ty: ast::mt,
208207
vst: ty::vstore,
209208
constr: fn(ty::mt) -> ty::t) -> ty::t
@@ -316,7 +315,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
316315
}
317316
ast::ty_rptr(region, mt) => {
318317
let r = ast_region_to_region(self, rscope, ast_ty.span, region);
319-
mk_pointer(self, in_anon_rscope(rscope, r), mt, ty::vstore_slice(r),
318+
let anon_rscope = in_anon_rscope(rscope, r);
319+
mk_pointer(self, &anon_rscope, mt, ty::vstore_slice(r),
320320
|tmt| ty::mk_rptr(tcx, r, tmt))
321321
}
322322
ast::ty_tup(fields) => {
@@ -419,8 +419,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
419419
}
420420

421421
pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
422-
self: @mut AC,
423-
rscope: RS,
422+
self: &AC,
423+
rscope: &RS,
424424
a: ast::arg,
425425
expected_ty: Option<ty::arg>)
426426
-> ty::arg {
@@ -467,8 +467,8 @@ pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
467467
}
468468

469469
pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
470-
self: @mut AC,
471-
rscope: RS,
470+
self: &AC,
471+
rscope: &RS,
472472
purity: ast::purity,
473473
abi: ast::Abi,
474474
decl: &ast::fn_decl)
@@ -479,10 +479,10 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
479479
// that function type
480480
let rb = in_binding_rscope(rscope);
481481

482-
let input_tys = decl.inputs.map(|a| ty_of_arg(self, rb, *a, None));
482+
let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None));
483483
let output_ty = match decl.output.node {
484484
ast::ty_infer => self.ty_infer(decl.output.span),
485-
_ => ast_ty_to_ty(self, rb, decl.output)
485+
_ => ast_ty_to_ty(self, &rb, decl.output)
486486
};
487487

488488
ty::BareFnTy {
@@ -493,8 +493,8 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
493493
}
494494

495495
pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
496-
self: @mut AC,
497-
rscope: RS,
496+
self: &AC,
497+
rscope: &RS,
498498
sigil: ast::Sigil,
499499
purity: ast::purity,
500500
onceness: ast::Onceness,
@@ -538,14 +538,14 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
538538
// were supplied
539539
if i < e.inputs.len() {Some(e.inputs[i])} else {None}
540540
};
541-
ty_of_arg(self, rb, *a, expected_arg_ty)
541+
ty_of_arg(self, &rb, *a, expected_arg_ty)
542542
};
543543

544544
let expected_ret_ty = expected_tys.map(|e| e.output);
545545
let output_ty = match decl.output.node {
546546
ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(),
547547
ast::ty_infer => self.ty_infer(decl.output.span),
548-
_ => ast_ty_to_ty(self, rb, decl.output)
548+
_ => ast_ty_to_ty(self, &rb, decl.output)
549549
};
550550

551551
ty::ClosureTy {

0 commit comments

Comments
 (0)