-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use local cache more often #18235
Use local cache more often #18235
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -844,19 +844,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
cache_skol_trait_ref: &Rc<ty::TraitRef>) | ||
-> &SelectionCache | ||
{ | ||
// High-level idea: we have to decide whether to consult the | ||
// cache that is specific to this scope, or to consult the | ||
// global cache. We want the cache that is specific to this | ||
// scope whenever where clauses might affect the result. | ||
|
||
// If the trait refers to any parameters in scope, then use | ||
// the cache of the param-environment. This is because the | ||
// result will depend on the where clauses that are in | ||
// scope. Otherwise, use the generic tcx cache, since the | ||
// result holds across all environments. | ||
// the cache of the param-environment. | ||
if | ||
cache_skol_trait_ref.input_types().iter().any( | ||
|&t| ty::type_has_self(t) || ty::type_has_params(t)) | ||
{ | ||
&self.param_env.selection_cache | ||
} else { | ||
&self.tcx().selection_cache | ||
return &self.param_env.selection_cache; | ||
} | ||
|
||
// If the trait refers to unbound type variables, and there | ||
// are where clauses in scope, then use the local environment. | ||
// If there are no where clauses in scope, which is a very | ||
// common case, then we can use the global environment. | ||
// See the discussion in doc.rs for more details. | ||
if | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a novel new coding style - are you experimenting? :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Somewhat. I just found it more readable that way. |
||
!self.param_env.caller_obligations.is_empty() | ||
&& | ||
cache_skol_trait_ref.input_types().iter().any( | ||
|&t| ty::type_has_ty_infer(t)) | ||
{ | ||
return &self.param_env.selection_cache; | ||
} | ||
|
||
// Otherwise, we can use the global cache. | ||
&self.tcx().selection_cache | ||
} | ||
|
||
fn check_candidate_cache(&mut self, | ||
|
@@ -1935,26 +1952,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
util::obligations_for_generics(self.tcx(), cause, recursion_depth, | ||
&impl_generics, impl_substs) | ||
} | ||
|
||
fn contains_skolemized_types(&self, | ||
ty: ty::t) | ||
-> bool | ||
{ | ||
/*! | ||
* True if the type contains skolemized variables. | ||
*/ | ||
|
||
let mut found_skol = false; | ||
|
||
ty::walk_ty(ty, |t| { | ||
match ty::get(t).sty { | ||
ty::ty_infer(ty::SkolemizedTy(_)) => { found_skol = true; } | ||
_ => { } | ||
} | ||
}); | ||
|
||
found_skol | ||
} | ||
} | ||
|
||
impl Repr for Candidate { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -585,18 +585,18 @@ pub struct ctxt<'tcx> { | |
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>, | ||
} | ||
|
||
pub enum tbox_flag { | ||
has_params = 1, | ||
has_self = 2, | ||
needs_infer = 4, | ||
has_regions = 8, | ||
has_ty_err = 16, | ||
has_ty_bot = 32, | ||
|
||
// a meta-pub flag: subst may be required if the type has parameters, a self | ||
// type, or references bound regions | ||
needs_subst = 1 | 2 | 8 | ||
} | ||
// Flags that we track on types. These flags are propagated upwards | ||
// through the type during type construction, so that we can quickly | ||
// check whether the type has various kinds of types in it without | ||
// recursing over the type itself. | ||
const HAS_PARAMS: uint = 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you create a type alias for uint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And preferably use |
||
const HAS_SELF: uint = 2; | ||
const HAS_TY_INFER: uint = 4; | ||
const HAS_RE_INFER: uint = 8; | ||
const HAS_REGIONS: uint = 16; | ||
const HAS_TY_ERR: uint = 32; | ||
const HAS_TY_BOT: uint = 64; | ||
const NEEDS_SUBST: uint = HAS_PARAMS | HAS_SELF | HAS_REGIONS; | ||
|
||
pub type t_box = &'static t_box_; | ||
|
||
|
@@ -631,15 +631,16 @@ pub fn get(t: t) -> t_box { | |
} | ||
} | ||
|
||
pub fn tbox_has_flag(tb: t_box, flag: tbox_flag) -> bool { | ||
(tb.flags & (flag as uint)) != 0u | ||
fn tbox_has_flag(tb: t_box, flag: uint) -> bool { | ||
(tb.flags & flag) != 0u | ||
} | ||
pub fn type_has_params(t: t) -> bool { | ||
tbox_has_flag(get(t), has_params) | ||
tbox_has_flag(get(t), HAS_PARAMS) | ||
} | ||
pub fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), has_self) } | ||
pub fn type_has_self(t: t) -> bool { tbox_has_flag(get(t), HAS_SELF) } | ||
pub fn type_has_ty_infer(t: t) -> bool { tbox_has_flag(get(t), HAS_TY_INFER) } | ||
pub fn type_needs_infer(t: t) -> bool { | ||
tbox_has_flag(get(t), needs_infer) | ||
tbox_has_flag(get(t), HAS_TY_INFER | HAS_RE_INFER) | ||
} | ||
pub fn type_id(t: t) -> uint { get(t).id } | ||
|
||
|
@@ -910,13 +911,13 @@ mod primitives { | |
pub static TY_BOT: t_box_ = t_box_ { | ||
sty: super::ty_bot, | ||
id: 16, | ||
flags: super::has_ty_bot as uint, | ||
flags: super::HAS_TY_BOT, | ||
}; | ||
|
||
pub static TY_ERR: t_box_ = t_box_ { | ||
sty: super::ty_err, | ||
id: 17, | ||
flags: super::has_ty_err as uint, | ||
flags: super::HAS_TY_ERR, | ||
}; | ||
|
||
pub const LAST_PRIMITIVE_ID: uint = 18; | ||
|
@@ -1579,9 +1580,9 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { | |
|
||
let mut flags = 0u; | ||
fn rflags(r: Region) -> uint { | ||
(has_regions as uint) | { | ||
HAS_REGIONS | { | ||
match r { | ||
ty::ReInfer(_) => needs_infer as uint, | ||
ty::ReInfer(_) => HAS_RE_INFER, | ||
_ => 0u | ||
} | ||
} | ||
|
@@ -1610,22 +1611,22 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { | |
&ty_str => {} | ||
// You might think that we could just return ty_err for | ||
// any type containing ty_err as a component, and get | ||
// rid of the has_ty_err flag -- likewise for ty_bot (with | ||
// rid of the HAS_TY_ERR flag -- likewise for ty_bot (with | ||
// the exception of function types that return bot). | ||
// But doing so caused sporadic memory corruption, and | ||
// neither I (tjc) nor nmatsakis could figure out why, | ||
// so we're doing it this way. | ||
&ty_bot => flags |= has_ty_bot as uint, | ||
&ty_err => flags |= has_ty_err as uint, | ||
&ty_bot => flags |= HAS_TY_BOT, | ||
&ty_err => flags |= HAS_TY_ERR, | ||
&ty_param(ref p) => { | ||
if p.space == subst::SelfSpace { | ||
flags |= has_self as uint; | ||
flags |= HAS_SELF; | ||
} else { | ||
flags |= has_params as uint; | ||
flags |= HAS_PARAMS; | ||
} | ||
} | ||
&ty_unboxed_closure(_, ref region) => flags |= rflags(*region), | ||
&ty_infer(_) => flags |= needs_infer as uint, | ||
&ty_infer(_) => flags |= HAS_TY_INFER, | ||
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { | ||
flags |= sflags(substs); | ||
} | ||
|
@@ -1648,7 +1649,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { | |
for a in f.sig.inputs.iter() { flags |= get(*a).flags; } | ||
flags |= get(f.sig.output).flags; | ||
// T -> _|_ is *not* _|_ ! | ||
flags &= !(has_ty_bot as uint); | ||
flags &= !HAS_TY_BOT; | ||
} | ||
&ty_closure(ref f) => { | ||
match f.store { | ||
|
@@ -1660,7 +1661,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { | |
for a in f.sig.inputs.iter() { flags |= get(*a).flags; } | ||
flags |= get(f.sig.output).flags; | ||
// T -> _|_ is *not* _|_ ! | ||
flags &= !(has_ty_bot as uint); | ||
flags &= !HAS_TY_BOT; | ||
flags |= flags_for_bounds(&f.bounds); | ||
} | ||
} | ||
|
@@ -1979,15 +1980,15 @@ impl ItemSubsts { | |
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil } | ||
|
||
pub fn type_is_bot(ty: t) -> bool { | ||
(get(ty).flags & (has_ty_bot as uint)) != 0 | ||
(get(ty).flags & HAS_TY_BOT) != 0 | ||
} | ||
|
||
pub fn type_is_error(ty: t) -> bool { | ||
(get(ty).flags & (has_ty_err as uint)) != 0 | ||
(get(ty).flags & HAS_TY_ERR) != 0 | ||
} | ||
|
||
pub fn type_needs_subst(ty: t) -> bool { | ||
tbox_has_flag(get(ty), needs_subst) | ||
tbox_has_flag(get(ty), NEEDS_SUBST) | ||
} | ||
|
||
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// 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 that the cache results from the default method do not pollute | ||
// the cache for the later call in `load()`. | ||
// | ||
// See issue #18209. | ||
|
||
pub trait Foo { | ||
fn load_from() -> Box<Self>; | ||
fn load() -> Box<Self> { | ||
Foo::load_from() | ||
} | ||
} | ||
|
||
pub fn load<M: Foo>() -> Box<M> { | ||
Foo::load() | ||
} | ||
|
||
fn main() { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'replay'?