diff options
| author | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
| commit | 522d09dfecbeca1595f25ac58c6d0178bbd21d7d (patch) | |
| tree | cc0252dd3413e5f890d0ebcfdaa096e5b002be0b /src/librustc/middle | |
| parent | 0b664bb8436f2cfda7f13a6f302ab486f332816f (diff) | |
| parent | 49771bafa5fca16486bfd06741dac3de2c587adf (diff) | |
| download | rust-1.0.0-alpha.2.tar.gz rust-1.0.0-alpha.2.zip | |
Auto merge of #22541 - Manishearth:rollup, r=Gankro 1.0.0-alpha.2
Continued from #22520
Diffstat (limited to 'src/librustc/middle')
32 files changed, 607 insertions, 300 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c3302debdfa..ae10eb686b0 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -134,7 +134,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, // Do an Option dance to use the path after it is moved below. let s = ast_map::path_to_string(path.iter().cloned()); path_as_str = Some(s); - path_as_str.as_ref().map(|x| &x[]) + path_as_str.as_ref().map(|x| &x[..]) }); let mut ast_dsr = reader::Decoder::new(ast_doc); let from_id_range = Decodable::decode(&mut ast_dsr).unwrap(); diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 1f0fe4f1aca..46b4a51c9d6 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -92,7 +92,7 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> { let s = replace_newline_with_backslash_l(s); label.push_str(&format!("exiting scope_{} {}", i, - &s[])[]); + &s[..])[]); } dot::LabelText::EscStr(label.into_cow()) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 03456f85290..86c59b24e3e 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -25,7 +25,7 @@ use middle::ty::*; use middle::ty; use std::cmp::Ordering; use std::fmt; -use std::iter::{range_inclusive, AdditiveIterator, FromIterator, repeat}; +use std::iter::{range_inclusive, AdditiveIterator, FromIterator, IntoIterator, repeat}; use std::num::Float; use std::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId, Pat}; @@ -76,7 +76,7 @@ impl<'a> fmt::Debug for Matrix<'a> { pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) }).collect(); - let total_width = column_widths.iter().map(|n| *n).sum() + column_count * 3 + 1; + let total_width = column_widths.iter().cloned().sum() + column_count * 3 + 1; let br = repeat('+').take(total_width).collect::<String>(); try!(write!(f, "{}\n", br)); for row in pretty_printed_matrix { @@ -94,8 +94,8 @@ impl<'a> fmt::Debug for Matrix<'a> { } impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> { - fn from_iter<T: Iterator<Item=Vec<&'a Pat>>>(iterator: T) -> Matrix<'a> { - Matrix(iterator.collect()) + fn from_iter<T: IntoIterator<Item=Vec<&'a Pat>>>(iter: T) -> Matrix<'a> { + Matrix(iter.into_iter().collect()) } } @@ -200,7 +200,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { } // Fourth, check for unreachable arms. - check_arms(cx, &inlined_arms[], source); + check_arms(cx, &inlined_arms[..], source); // Finally, check if the whole match expression is exhaustive. // Check for empty enum, because is_useful only works on inhabited types. @@ -291,7 +291,7 @@ fn check_arms(cx: &MatchCheckCtxt, for pat in pats { let v = vec![&**pat]; - match is_useful(cx, &seen, &v[], LeaveOutWitness) { + match is_useful(cx, &seen, &v[..], LeaveOutWitness) { NotUseful => { match source { ast::MatchSource::IfLetDesugar { .. } => { @@ -351,7 +351,7 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: ast::MatchSource) { match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { UsefulWithWitness(pats) => { - let witness = match &pats[] { + let witness = match &pats[..] { [ref witness] => &**witness, [] => DUMMY_WILD_PAT, _ => unreachable!() @@ -360,7 +360,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: ast: ast::MatchSource::ForLoopDesugar => { // `witness` has the form `Some(<head>)`, peel off the `Some` let witness = match witness.node { - ast::PatEnum(_, Some(ref pats)) => match &pats[] { + ast::PatEnum(_, Some(ref pats)) => match &pats[..] { [ref pat] => &**pat, _ => unreachable!(), }, @@ -664,7 +664,7 @@ fn is_useful(cx: &MatchCheckCtxt, UsefulWithWitness(pats) => UsefulWithWitness({ let arity = constructor_arity(cx, &c, left_ty); let mut result = { - let pat_slice = &pats[]; + let pat_slice = &pats[..]; let subpats: Vec<_> = (0..arity).map(|i| { pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p) }).collect(); @@ -711,10 +711,10 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, witness: WitnessPreference) -> Usefulness { let arity = constructor_arity(cx, &ctor, lty); let matrix = Matrix(m.iter().filter_map(|r| { - specialize(cx, &r[], &ctor, 0, arity) + specialize(cx, &r[..], &ctor, 0, arity) }).collect()); match specialize(cx, v, &ctor, 0, arity) { - Some(v) => is_useful(cx, &matrix, &v[], witness), + Some(v) => is_useful(cx, &matrix, &v[..], witness), None => NotUseful } } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 3d03cd946c4..5bf7422dbc0 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -62,7 +62,7 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, None => None, Some(ast_map::NodeItem(it)) => match it.node { ast::ItemEnum(ast::EnumDef { ref variants }, _) => { - variant_expr(&variants[], variant_def.node) + variant_expr(&variants[..], variant_def.node) } _ => None }, @@ -83,7 +83,7 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, // NOTE this doesn't do the right thing, it compares inlined // NodeId's to the original variant_def's NodeId, but they // come from different crates, so they will likely never match. - variant_expr(&variants[], variant_def.node).map(|e| e.id) + variant_expr(&variants[..], variant_def.node).map(|e| e.id) } _ => None }, @@ -209,7 +209,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val { match eval_const_expr_partial(tcx, e, None) { Ok(r) => r, - Err(s) => tcx.sess.span_fatal(e.span, &s[]) + Err(s) => tcx.sess.span_fatal(e.span, &s[..]) } } @@ -501,7 +501,7 @@ fn lit_to_const(lit: &ast::Lit, ty_hint: Option<Ty>) -> const_val { match lit.node { ast::LitStr(ref s, _) => const_str((*s).clone()), ast::LitBinary(ref data) => { - const_binary(Rc::new(data.iter().map(|x| *x).collect())) + const_binary(data.clone()) } ast::LitByte(n) => const_uint(n as u64), ast::LitChar(n) => const_uint(n as u64), @@ -552,14 +552,14 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, let a = match eval_const_expr_partial(tcx, a, ty_hint) { Ok(a) => a, Err(s) => { - tcx.sess.span_err(a.span, &s[]); + tcx.sess.span_err(a.span, &s[..]); return None; } }; let b = match eval_const_expr_partial(tcx, b, ty_hint) { Ok(b) => b, Err(s) => { - tcx.sess.span_err(b.span, &s[]); + tcx.sess.span_err(b.span, &s[..]); return None; } }; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index b792a44d4d8..085d5cbc347 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -89,7 +89,7 @@ struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> { } fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex { - let opt_cfgindex = index.get(&id).map(|&i|i); + let opt_cfgindex = index.get(&id).cloned(); opt_cfgindex.unwrap_or_else(|| { panic!("nodeid_to_index does not have entry for NodeId {}", id); }) @@ -312,7 +312,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let mut t = on_entry.to_vec(); self.apply_gen_kill(cfgidx, &mut t); temp_bits = t; - &temp_bits[] + &temp_bits[..] } }; debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}", @@ -400,7 +400,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let mut changed = false; for &node_id in &edge.data.exiting_scopes { - let opt_cfg_idx = self.nodeid_to_index.get(&node_id).map(|&i|i); + let opt_cfg_idx = self.nodeid_to_index.get(&node_id).cloned(); match opt_cfg_idx { Some(cfg_idx) => { let (start, end) = self.compute_id_range(cfg_idx); @@ -421,7 +421,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let bits = &mut self.kills[start.. end]; debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); - bits.clone_from_slice(&orig_kills[]); + bits.clone_from_slice(&orig_kills[..]); debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index b2335f91ad9..ff78deb8d12 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -321,7 +321,7 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { for attr in lint::gather_attrs(attrs) { match attr { Ok((ref name, lint::Allow, _)) - if &name[] == dead_code => return true, + if &name[..] == dead_code => return true, _ => (), } } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 6d35a82d153..ad9f4eade5c 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -158,7 +158,7 @@ fn calculate_type(sess: &session::Session, // Collect what we've got so far in the return vector. let mut ret = (1..sess.cstore.next_crate_num()).map(|i| { - match formats.get(&i).map(|v| *v) { + match formats.get(&i).cloned() { v @ Some(cstore::RequireDynamic) => v, _ => None, } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8dbac7f515e..e99d214742a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -29,7 +29,6 @@ use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam}; use middle::ty::{MethodStatic, MethodStaticClosure}; use util::ppaux::Repr; -use std::marker; use syntax::{ast, ast_util}; use syntax::ptr::P; use syntax::codemap::Span; @@ -128,16 +127,14 @@ pub enum MatchMode { MovingMatch, } -#[derive(PartialEq,Debug)] -enum TrackMatchMode<T> { +#[derive(Copy, PartialEq, Debug)] +enum TrackMatchMode { Unknown, Definite(MatchMode), Conflicting, } -impl<T> marker::Copy for TrackMatchMode<T> {} - -impl<T> TrackMatchMode<T> { +impl TrackMatchMode { // Builds up the whole match mode for a pattern from its constituent // parts. The lattice looks like this: // @@ -931,7 +928,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { return true; } - fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) -> TrackMatchMode<Span> { + fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) -> TrackMatchMode { let mut mode = Unknown; for pat in &arm.pats { self.determine_pat_move_mode(discr_cmt.clone(), &**pat, &mut mode); @@ -966,7 +963,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { fn determine_pat_move_mode(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &ast::Pat, - mode: &mut TrackMatchMode<Span>) { + mode: &mut TrackMatchMode) { debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()), pat.repr(self.tcx())); return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| { @@ -1166,7 +1163,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { let msg = format!("Pattern has unexpected def: {:?} and type {}", def, cmt_pat.ty.repr(tcx)); - tcx.sess.span_bug(pat.span, &msg[]) + tcx.sess.span_bug(pat.span, &msg[..]) } } } diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 4dd7a4a2266..436f04fc9e9 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -34,7 +34,7 @@ use std::fmt::{Formatter, Error, Debug}; use std::usize; -use std::collections::BitvSet; +use std::collections::BitSet; pub struct Graph<N,E> { nodes: Vec<Node<N>> , @@ -292,7 +292,7 @@ impl<N,E> Graph<N,E> { DepthFirstTraversal { graph: self, stack: vec![start], - visited: BitvSet::new() + visited: BitSet::new() } } } @@ -300,7 +300,7 @@ impl<N,E> Graph<N,E> { pub struct DepthFirstTraversal<'g, N:'g, E:'g> { graph: &'g Graph<N, E>, stack: Vec<NodeIndex>, - visited: BitvSet + visited: BitSet } impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> { diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs new file mode 100644 index 00000000000..93c80fb754f --- /dev/null +++ b/src/librustc/middle/infer/bivariate.rs @@ -0,0 +1,145 @@ +// 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. + +//! Applies the "bivariance relationship" to two types and/or regions. +//! If (A,B) are bivariant then either A <: B or B <: A. It occurs +//! when type/lifetime parameters are unconstrained. Usually this is +//! an error, but we permit it in the specific case where a type +//! parameter is constrained in a where-clause via an associated type. +//! +//! There are several ways one could implement bivariance. You could +//! just do nothing at all, for example, or you could fully verify +//! that one of the two subtyping relationships hold. We choose to +//! thread a middle line: we relate types up to regions, but ignore +//! all region relationships. +//! +//! At one point, handling bivariance in this fashion was necessary +//! for inference, but I'm actually not sure if that is true anymore. +//! In particular, it might be enough to say (A,B) are bivariant for +//! all (A,B). + +use middle::ty::{BuiltinBounds}; +use middle::ty::{self, Ty}; +use middle::ty::TyVar; +use middle::infer::combine::*; +use middle::infer::{cres}; +use middle::infer::type_variable::{BiTo}; +use util::ppaux::{Repr}; + +use syntax::ast::{Unsafety}; + +pub struct Bivariate<'f, 'tcx: 'f> { + fields: CombineFields<'f, 'tcx> +} + +#[allow(non_snake_case)] +pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> { + Bivariate { fields: cf } +} + +impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { + fn tag(&self) -> String { "Bivariate".to_string() } + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } + + fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>> + { + match v { + ty::Invariant => self.equate().tys(a, b), + ty::Covariant => self.tys(a, b), + ty::Contravariant => self.tys(a, b), + ty::Bivariant => self.tys(a, b), + } + } + + fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region> + { + match v { + ty::Invariant => self.equate().regions(a, b), + ty::Covariant => self.regions(a, b), + ty::Contravariant => self.regions(a, b), + ty::Bivariant => self.regions(a, b), + } + } + + fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> { + Ok(a) + } + + fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> { + debug!("mts({} <: {})", + a.repr(self.fields.infcx.tcx), + b.repr(self.fields.infcx.tcx)); + + if a.mutbl != b.mutbl { return Err(ty::terr_mutability); } + let t = try!(self.tys(a.ty, b.ty)); + Ok(ty::mt { mutbl: a.mutbl, ty: t }) + } + + fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> { + if a != b { + Err(ty::terr_unsafety_mismatch(expected_found(self, a, b))) + } else { + Ok(a) + } + } + + fn builtin_bounds(&self, + a: BuiltinBounds, + b: BuiltinBounds) + -> cres<'tcx, BuiltinBounds> + { + if a != b { + Err(ty::terr_builtin_bounds(expected_found(self, a, b))) + } else { + Ok(a) + } + } + + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + debug!("{}.tys({}, {})", self.tag(), + a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); + if a == b { return Ok(a); } + + let infcx = self.fields.infcx; + let a = infcx.type_variables.borrow().replace_if_possible(a); + let b = infcx.type_variables.borrow().replace_if_possible(b); + match (&a.sty, &b.sty) { + (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => { + infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); + Ok(a) + } + + (&ty::ty_infer(TyVar(a_id)), _) => { + try!(self.fields.instantiate(b, BiTo, a_id)); + Ok(a) + } + + (_, &ty::ty_infer(TyVar(b_id))) => { + try!(self.fields.instantiate(a, BiTo, b_id)); + Ok(a) + } + + _ => { + super_tys(self, a, b) + } + } + } + + fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>> + where T : Combineable<'tcx> + { + let a1 = ty::erase_late_bound_regions(self.tcx(), a); + let b1 = ty::erase_late_bound_regions(self.tcx(), b); + let c = try!(Combineable::combine(self, &a1, &b1)); + Ok(ty::Binder(c)) + } +} diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index daa820f43b5..0eeafb767d8 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -32,6 +32,7 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::bivariate::Bivariate; use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; @@ -39,7 +40,7 @@ use super::sub::Sub; use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; use super::{InferCtxt, cres}; use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, EqTo, SubtypeOf, SupertypeOf}; +use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use middle::subst; use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; @@ -48,7 +49,7 @@ use middle::ty::{IntType, UintType}; use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; use middle::ty_fold; -use middle::ty_fold::{TypeFoldable}; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use util::ppaux::Repr; use std::rc::Rc; @@ -58,41 +59,32 @@ use syntax::abi; use syntax::codemap::Span; pub trait Combine<'tcx> : Sized { - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>; fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx } fn tag(&self) -> String; - fn a_is_expected(&self) -> bool; - fn trace(&self) -> TypeTrace<'tcx>; - fn equate<'a>(&'a self) -> Equate<'a, 'tcx>; - fn sub<'a>(&'a self) -> Sub<'a, 'tcx>; - fn lub<'a>(&'a self) -> Lub<'a, 'tcx>; - fn glb<'a>(&'a self) -> Glb<'a, 'tcx>; + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>; + + fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx } + fn a_is_expected(&self) -> bool { self.fields().a_is_expected } + fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() } + fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() } + fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() } + + fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() } + fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) } + fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) } fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>>; - fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>; + + fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>>; + fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>; - fn tps(&self, - _: subst::ParamSpace, - as_: &[Ty<'tcx>], - bs: &[Ty<'tcx>]) - -> cres<'tcx, Vec<Ty<'tcx>>> { - // FIXME -- In general, we treat variance a bit wrong - // here. For historical reasons, we treat tps and Self - // as invariant. This is overly conservative. - - if as_.len() != bs.len() { - return Err(ty::terr_ty_param_size(expected_found(self, - as_.len(), - bs.len()))); - } + fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region>; - try!(as_.iter().zip(bs.iter()) - .map(|(a, b)| self.equate().tys(*a, *b)) - .collect::<cres<Vec<Ty>>>()); - Ok(as_.to_vec()) - } + fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>; fn substs(&self, item_def_id: ast::DefId, @@ -100,6 +92,11 @@ pub trait Combine<'tcx> : Sized { b_subst: &subst::Substs<'tcx>) -> cres<'tcx, subst::Substs<'tcx>> { + debug!("substs: item_def_id={} a_subst={} b_subst={}", + item_def_id.repr(self.infcx().tcx), + a_subst.repr(self.infcx().tcx), + b_subst.repr(self.infcx().tcx)); + let variances = if self.infcx().tcx.variance_computed.get() { Some(ty::item_variances(self.infcx().tcx, item_def_id)) } else { @@ -119,7 +116,8 @@ pub trait Combine<'tcx> : Sized { for &space in &subst::ParamSpace::all() { let a_tps = a_subst.types.get_slice(space); let b_tps = b_subst.types.get_slice(space); - let tps = try!(self.tps(space, a_tps, b_tps)); + let t_variances = variances.map(|v| v.types.get_slice(space)); + let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps)); substs.types.replace(space, tps); } @@ -132,20 +130,7 @@ pub trait Combine<'tcx> : Sized { for &space in &subst::ParamSpace::all() { let a_regions = a.get_slice(space); let b_regions = b.get_slice(space); - - let mut invariance = Vec::new(); - let r_variances = match variances { - Some(variances) => { - variances.regions.get_slice(space) - } - None => { - for _ in a_regions { - invariance.push(ty::Invariant); - } - &invariance[] - } - }; - + let r_variances = variances.map(|v| v.regions.get_slice(space)); let regions = try!(relate_region_params(self, r_variances, a_regions, @@ -157,13 +142,34 @@ pub trait Combine<'tcx> : Sized { return Ok(substs); + fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C, + variances: Option<&[ty::Variance]>, + a_tys: &[Ty<'tcx>], + b_tys: &[Ty<'tcx>]) + -> cres<'tcx, Vec<Ty<'tcx>>> + { + if a_tys.len() != b_tys.len() { + return Err(ty::terr_ty_param_size(expected_found(this, + a_tys.len(), + b_tys.len()))); + } + + range(0, a_tys.len()).map(|i| { + let a_ty = a_tys[i]; + let b_ty = b_tys[i]; + let v = variances.map_or(ty::Invariant, |v| v[i]); + this.tys_with_variance(v, a_ty, b_ty) + }).collect() + } + fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C, - variances: &[ty::Variance], + variances: Option<&[ty::Variance]>, a_rs: &[ty::Region], b_rs: &[ty::Region]) - -> cres<'tcx, Vec<ty::Region>> { + -> cres<'tcx, Vec<ty::Region>> + { let tcx = this.infcx().tcx; - let num_region_params = variances.len(); + let num_region_params = a_rs.len(); debug!("relate_region_params(\ a_rs={}, \ @@ -173,22 +179,18 @@ pub trait Combine<'tcx> : Sized { b_rs.repr(tcx), variances.repr(tcx)); - assert_eq!(num_region_params, a_rs.len()); + assert_eq!(num_region_params, + variances.map_or(num_region_params, + |v| v.len())); + assert_eq!(num_region_params, b_rs.len()); - let mut rs = vec!(); - for i in 0..num_region_params { + + (0..a_rs.len()).map(|i| { let a_r = a_rs[i]; let b_r = b_rs[i]; - let variance = variances[i]; - let r = match variance { - ty::Invariant => this.equate().regions(a_r, b_r), - ty::Covariant => this.regions(a_r, b_r), - ty::Contravariant => this.contraregions(a_r, b_r), - ty::Bivariant => Ok(a_r), - }; - rs.push(try!(r)); - } - Ok(rs) + let variance = variances.map_or(ty::Invariant, |v| v[i]); + this.regions_with_variance(variance, a_r, b_r) + }).collect() } } @@ -241,7 +243,7 @@ pub trait Combine<'tcx> : Sized { } fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - self.contratys(a, b).and_then(|t| Ok(t)) + self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t)) } fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety>; @@ -309,7 +311,7 @@ pub trait Combine<'tcx> : Sized { b: &ty::ExistentialBounds<'tcx>) -> cres<'tcx, ty::ExistentialBounds<'tcx>> { - let r = try!(self.contraregions(a.region_bound, b.region_bound)); + let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound)); let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds)); Ok(ty::ExistentialBounds { region_bound: r, @@ -322,11 +324,6 @@ pub trait Combine<'tcx> : Sized { b: ty::BuiltinBounds) -> cres<'tcx, ty::BuiltinBounds>; - fn contraregions(&self, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region>; - - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>; - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) @@ -540,7 +537,8 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, } (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => { - let r = try!(this.contraregions(*a_r, *b_r)); + let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r)); + // FIXME(14985) If we have mutable references to trait objects, we // used to use covariant subtyping. I have preserved this behaviour, // even though it is probably incorrect. So don't go down the usual @@ -644,6 +642,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { Equate((*self).clone()) } + fn bivariate(&self) -> Bivariate<'f, 'tcx> { + Bivariate((*self).clone()) + } + fn sub(&self) -> Sub<'f, 'tcx> { Sub((*self).clone()) } @@ -697,7 +699,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { EqTo => { self.generalize(a_ty, b_vid, false) } - SupertypeOf | SubtypeOf => { + BiTo | SupertypeOf | SubtypeOf => { self.generalize(a_ty, b_vid, true) } }); @@ -721,6 +723,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { + BiTo => { + try!(self.bivariate().tys(a_ty, b_ty)); + } + EqTo => { try!(self.equate().tys(a_ty, b_ty)); } @@ -730,7 +736,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { } SupertypeOf => { - try!(self.sub().contratys(a_ty, b_ty)); + try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)); } } } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index f0bde222864..7194e20b0cf 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -13,11 +13,7 @@ use middle::ty::{self, Ty}; use middle::ty::TyVar; use middle::infer::combine::*; use middle::infer::{cres}; -use middle::infer::glb::Glb; -use middle::infer::InferCtxt; -use middle::infer::lub::Lub; -use middle::infer::sub::Sub; -use middle::infer::{TypeTrace, Subtype}; +use middle::infer::{Subtype}; use middle::infer::type_variable::{EqTo}; use util::ppaux::{Repr}; @@ -33,21 +29,20 @@ pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> { } impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx } - fn tag(&self) -> String { "eq".to_string() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() } + fn tag(&self) -> String { "Equate".to_string() } + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) } - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) } - - fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>> + { + // Once we're equating, it doesn't matter what the variance is. self.tys(a, b) } - fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region> + { + // Once we're equating, it doesn't matter what the variance is. self.regions(a, b) } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 72b33613c66..53032f9b9ac 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -200,9 +200,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ref trace_origins, ref same_regions) => { if !same_regions.is_empty() { - self.report_processed_errors(&var_origins[], - &trace_origins[], - &same_regions[]); + self.report_processed_errors(&var_origins[..], + &trace_origins[..], + &same_regions[..]); } } } @@ -675,6 +675,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup, ""); } + infer::Operand(span) => { + self.tcx.sess.span_err( + span, + "lifetime of operand does not outlive \ + the operation"); + note_and_explain_region( + self.tcx, + "the operand is only valid for ", + sup, + ""); + } infer::AddrOf(span) => { self.tcx.sess.span_err( span, @@ -824,7 +835,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { let parent = self.tcx.map.get_parent(scope_id); let parent_node = self.tcx.map.find(parent); let taken = lifetimes_in_scope(self.tcx, scope_id); - let life_giver = LifeGiver::with_taken(&taken[]); + let life_giver = LifeGiver::with_taken(&taken[..]); let node_inner = match parent_node { Some(ref node) => match *node { ast_map::NodeItem(ref item) => { @@ -924,7 +935,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { fn rebuild(&self) -> (ast::FnDecl, Option<ast::ExplicitSelf_>, ast::Generics) { - let mut expl_self_opt = self.expl_self_opt.map(|x| x.clone()); + let mut expl_self_opt = self.expl_self_opt.cloned(); let mut inputs = self.fn_decl.inputs.clone(); let mut output = self.fn_decl.output.clone(); let mut ty_params = self.generics.ty_params.clone(); @@ -942,7 +953,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime, &anon_nums, ®ion_names); - inputs = self.rebuild_args_ty(&inputs[], lifetime, + inputs = self.rebuild_args_ty(&inputs[..], lifetime, &anon_nums, ®ion_names); output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names); ty_params = self.rebuild_ty_params(ty_params, lifetime, @@ -1426,7 +1437,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { opt_explicit_self, generics); let msg = format!("consider using an explicit lifetime \ parameter as shown: {}", suggested_fn); - self.tcx.sess.span_help(span, &msg[]); + self.tcx.sess.span_help(span, &msg[..]); } fn report_inference_failure(&self, @@ -1593,6 +1604,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { span, "...so that return value is valid for the call"); } + infer::Operand(span) => { + self.tcx.sess.span_err( + span, + "...so that operand is valid for operation"); + } infer::AddrOf(span) => { self.tcx.sess.span_note( span, @@ -1771,7 +1787,7 @@ impl LifeGiver { s.push_str(&num_to_string(self.counter.get())[]); if !self.taken.contains(&s) { lifetime = name_to_dummy_lifetime( - token::str_to_ident(&s[]).name); + token::str_to_ident(&s[..]).name); self.generated.borrow_mut().push(lifetime); break; } diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index ff0c2d92f45..33303808e84 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -10,12 +10,9 @@ use super::combine::*; use super::lattice::*; -use super::equate::Equate; use super::higher_ranked::HigherRankedRelations; -use super::lub::Lub; -use super::sub::Sub; -use super::{cres, InferCtxt}; -use super::{TypeTrace, Subtype}; +use super::{cres}; +use super::Subtype; use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; @@ -34,15 +31,30 @@ pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> { } impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx } - fn tag(&self) -> String { "glb".to_string() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() } + fn tag(&self) -> String { "Glb".to_string() } + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) } - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) } + fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>> + { + match v { + ty::Invariant => self.equate().tys(a, b), + ty::Covariant => self.tys(a, b), + ty::Bivariant => self.bivariate().tys(a, b), + ty::Contravariant => self.lub().tys(a, b), + } + } + + fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region> + { + match v { + ty::Invariant => self.equate().regions(a, b), + ty::Covariant => self.regions(a, b), + ty::Bivariant => self.bivariate().regions(a, b), + ty::Contravariant => self.lub().regions(a, b), + } + } fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> { let tcx = self.fields.infcx.tcx; @@ -75,10 +87,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { } } - fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - self.lub().tys(a, b) - } - fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> { match (a, b) { (Unsafety::Normal, _) | (_, Unsafety::Normal) => Ok(Unsafety::Normal), @@ -104,11 +112,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) } - fn contraregions(&self, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> { - self.lub().regions(a, b) - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 4469e27a5b0..a729156c88b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -31,7 +31,7 @@ pub trait HigherRankedRelations<'tcx> { where T : Combineable<'tcx>; } -trait InferCtxtExt<'tcx> { +trait InferCtxtExt { fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>; fn region_vars_confined_to_snapshot(&self, @@ -371,7 +371,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, })) } -impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { +impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region> { self.region_vars.tainted(&snapshot.region_vars_snapshot, r) } diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 204560e87ee..3570effa9fa 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -9,13 +9,10 @@ // except according to those terms. use super::combine::*; -use super::equate::Equate; -use super::glb::Glb; use super::higher_ranked::HigherRankedRelations; use super::lattice::*; -use super::sub::Sub; -use super::{cres, InferCtxt}; -use super::{TypeTrace, Subtype}; +use super::{cres}; +use super::{Subtype}; use middle::ty::{BuiltinBounds}; use middle::ty::{self, Ty}; @@ -34,15 +31,30 @@ pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> { } impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx } - fn tag(&self) -> String { "lub".to_string() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() } + fn tag(&self) -> String { "Lub".to_string() } + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) } - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) } + fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>> + { + match v { + ty::Invariant => self.equate().tys(a, b), + ty::Covariant => self.tys(a, b), + ty::Bivariant => self.bivariate().tys(a, b), + ty::Contravariant => self.glb().tys(a, b), + } + } + + fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region> + { + match v { + ty::Invariant => self.equate().regions(a, b), + ty::Covariant => self.regions(a, b), + ty::Bivariant => self.bivariate().regions(a, b), + ty::Contravariant => self.glb().regions(a, b), + } + } fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> { let tcx = self.tcx(); @@ -70,10 +82,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { } } - fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - self.glb().tys(a, b) - } - fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> { match (a, b) { (Unsafety::Unsafe, _) | (_, Unsafety::Unsafe) => Ok(Unsafety::Unsafe), @@ -90,11 +98,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { Ok(a.intersection(b)) } - fn contraregions(&self, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> { - self.glb().regions(a, b) - } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 00e377d65fe..b0576ff55ff 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -45,6 +45,7 @@ use self::lub::Lub; use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes}; use self::error_reporting::ErrorReporting; +pub mod bivariate; pub mod combine; pub mod equate; pub mod error_reporting; @@ -209,6 +210,9 @@ pub enum SubregionOrigin<'tcx> { // Region in return type of invoked fn must enclose call CallReturn(Span), + // Operands must be in scope + Operand(Span), + // Region resulting from a `&` expr must enclose the `&` expr AddrOf(Span), @@ -1194,6 +1198,7 @@ impl<'tcx> SubregionOrigin<'tcx> { CallRcvr(a) => a, CallArg(a) => a, CallReturn(a) => a, + Operand(a) => a, AddrOf(a) => a, AutoBorrow(a) => a, SafeDestructor(a) => a, @@ -1257,6 +1262,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> { CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)), CallArg(a) => format!("CallArg({})", a.repr(tcx)), CallReturn(a) => format!("CallReturn({})", a.repr(tcx)), + Operand(a) => format!("Operand({})", a.repr(tcx)), AddrOf(a) => format!("AddrOf({})", a.repr(tcx)), AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)), SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)), diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 5cdfdcc7c9b..b4fd34f206f 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -977,7 +977,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { self.expansion(&mut var_data); self.contraction(&mut var_data); let values = - self.extract_values_and_collect_conflicts(&var_data[], + self.extract_values_and_collect_conflicts(&var_data[..], errors); self.collect_concrete_region_errors(&values, errors); values diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 1e0d14544ff..33da3092b2a 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -10,12 +10,8 @@ use super::combine::*; use super::{cres, CresCompare}; -use super::equate::Equate; -use super::glb::Glb; use super::higher_ranked::HigherRankedRelations; -use super::InferCtxt; -use super::lub::Lub; -use super::{TypeTrace, Subtype}; +use super::{Subtype}; use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{BuiltinBounds}; @@ -37,28 +33,30 @@ pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> { } impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx } - fn tag(&self) -> String { "sub".to_string() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() } - - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) } - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) } - - fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - Sub(self.fields.switch_expected()).tys(b, a) + fn tag(&self) -> String { "Sub".to_string() } + fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } + + fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) + -> cres<'tcx, Ty<'tcx>> + { + match v { + ty::Invariant => self.equate().tys(a, b), + ty::Covariant => self.tys(a, b), + ty::Bivariant => self.bivariate().tys(a, b), + ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a), + } } - fn contraregions(&self, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> { - let opp = CombineFields { - a_is_expected: !self.fields.a_is_expected, - ..self.fields.clone() - }; - Sub(opp).regions(b, a) - } + fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) + -> cres<'tcx, ty::Region> + { + match v { + ty::Invariant => self.equate().regions(a, b), + ty::Covariant => self.regions(a, b), + ty::Bivariant => self.bivariate().regions(a, b), + ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a), + } + } fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { debug!("{}.regions({}, {})", diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 9b8a4a84412..a856137af09 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -14,6 +14,7 @@ use self::UndoEntry::*; use middle::ty::{self, Ty}; use std::cmp::min; +use std::marker::PhantomData; use std::mem; use std::u32; use util::snapshot_vec as sv; @@ -42,13 +43,13 @@ enum UndoEntry { Relate(ty::TyVid, ty::TyVid), } -struct Delegate<'tcx>; +struct Delegate<'tcx>(PhantomData<&'tcx ()>); type Relation = (RelationDir, ty::TyVid); #[derive(Copy, PartialEq, Debug)] pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo + SubtypeOf, SupertypeOf, EqTo, BiTo } impl RelationDir { @@ -56,14 +57,15 @@ impl RelationDir { match self { SubtypeOf => SupertypeOf, SupertypeOf => SubtypeOf, - EqTo => EqTo + EqTo => EqTo, + BiTo => BiTo, } } } impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { values: sv::SnapshotVec::new(Delegate) } + TypeVariableTable { values: sv::SnapshotVec::new(Delegate(PhantomData)) } } fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> { diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 235f3f994c6..0675cec6f69 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -18,6 +18,7 @@ use middle::infer::{uok, ures}; use middle::infer::InferCtxt; use std::cell::RefCell; use std::fmt::Debug; +use std::marker::PhantomData; use syntax::ast; use util::snapshot_vec as sv; @@ -79,7 +80,7 @@ pub struct UnificationTable<K:UnifyKey> { /// made during the snapshot may either be *committed* or *rolled back*. pub struct Snapshot<K:UnifyKey> { // Link snapshot to the key type `K` of the table. - marker: marker::CovariantType<K>, + marker: marker::PhantomData<K>, snapshot: sv::Snapshot, } @@ -92,7 +93,7 @@ pub struct Node<K:UnifyKey> { } #[derive(Copy)] -pub struct Delegate<K>; +pub struct Delegate<K>(PhantomData<K>); // We can't use V:LatticeValue, much as I would like to, // because frequently the pattern is that V=Option<U> for some @@ -102,14 +103,14 @@ pub struct Delegate<K>; impl<K:UnifyKey> UnificationTable<K> { pub fn new() -> UnificationTable<K> { UnificationTable { - values: sv::SnapshotVec::new(Delegate), + values: sv::SnapshotVec::new(Delegate(PhantomData)), } } /// Starts a new snapshot. Each snapshot must be either /// rolled back or committed in a "LIFO" (stack) order. pub fn snapshot(&mut self) -> Snapshot<K> { - Snapshot { marker: marker::CovariantType::<K>, + Snapshot { marker: marker::PhantomData::<K>, snapshot: self.values.start_snapshot() } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index e13a5672778..56c5928a132 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -147,18 +147,12 @@ struct LanguageItemCollector<'a> { impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> { fn visit_item(&mut self, item: &ast::Item) { - match extract(&item.attrs) { - Some(value) => { - let item_index = self.item_refs.get(&value[]).map(|x| *x); - - match item_index { - Some(item_index) => { - self.collect_item(item_index, local_def(item.id), item.span) - } - None => {} - } + if let Some(value) = extract(&item.attrs) { + let item_index = self.item_refs.get(&value[..]).cloned(); + + if let Some(item_index) = item_index { + self.collect_item(item_index, local_def(item.id), item.span) } - None => {} } visit::walk_item(self, item); @@ -312,12 +306,13 @@ lets_do_this! { ExchangeHeapLangItem, "exchange_heap", exchange_heap; OwnedBoxLangItem, "owned_box", owned_box; + PhantomFnItem, "phantom_fn", phantom_fn; PhantomDataItem, "phantom_data", phantom_data; + // Deprecated: CovariantTypeItem, "covariant_type", covariant_type; ContravariantTypeItem, "contravariant_type", contravariant_type; InvariantTypeItem, "invariant_type", invariant_type; - CovariantLifetimeItem, "covariant_lifetime", covariant_lifetime; ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime; InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d4fe0979313..e58136fb3f4 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1119,7 +1119,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Uninteresting cases: just propagate in rev exec order ast::ExprVec(ref exprs) => { - self.propagate_through_exprs(&exprs[], succ) + self.propagate_through_exprs(&exprs[..], succ) } ast::ExprRepeat(ref element, ref count) => { @@ -1143,7 +1143,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } else { succ }; - let succ = self.propagate_through_exprs(&args[], succ); + let succ = self.propagate_through_exprs(&args[..], succ); self.propagate_through_expr(&**f, succ) } @@ -1156,11 +1156,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } else { succ }; - self.propagate_through_exprs(&args[], succ) + self.propagate_through_exprs(&args[..], succ) } ast::ExprTup(ref exprs) => { - self.propagate_through_exprs(&exprs[], succ) + self.propagate_through_exprs(&exprs[..], succ) } ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op.node) => { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2f0462ab8c3..e539f6ae6cb 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -407,7 +407,7 @@ impl RegionMaps { pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> { //! Returns the narrowest scope that encloses `id`, if any. - self.scope_map.borrow().get(&id).map(|x| *x) + self.scope_map.borrow().get(&id).cloned() } #[allow(dead_code)] // used in middle::cfg diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e91d7d8c52c..3ba08c10320 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -562,7 +562,7 @@ pub fn early_bound_lifetimes<'a>(generics: &'a ast::Generics) -> Vec<ast::Lifeti generics.lifetimes.iter() .filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name)) - .map(|l| (*l).clone()) + .cloned() .collect() } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 9bf35bd4284..04fd03ab342 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -113,7 +113,7 @@ impl<'tcx> Substs<'tcx> { } pub fn self_ty(&self) -> Option<Ty<'tcx>> { - self.types.get_self().map(|&t| t) + self.types.get_self().cloned() } pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 3a7522cafee..e199a60c370 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -10,24 +10,27 @@ //! See `doc.rs` for high-level documentation +use super::Normalized; use super::SelectionContext; -use super::{Obligation, ObligationCause}; +use super::{ObligationCause}; +use super::PredicateObligation; use super::project; use super::util; use middle::subst::{Subst, TypeSpace}; -use middle::ty::{self, Ty}; -use middle::infer::InferCtxt; +use middle::ty::{self, ToPolyTraitRef, Ty}; +use middle::infer::{self, InferCtxt}; use std::collections::HashSet; use std::rc::Rc; use syntax::ast; use syntax::codemap::DUMMY_SP; use util::ppaux::Repr; -pub fn impl_can_satisfy(infcx: &InferCtxt, - impl1_def_id: ast::DefId, - impl2_def_id: ast::DefId) - -> bool +/// True if there exist types that satisfy both of the two given impls. +pub fn overlapping_impls(infcx: &InferCtxt, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + -> bool { debug!("impl_can_satisfy(\ impl1_def_id={}, \ @@ -35,28 +38,68 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, impl1_def_id.repr(infcx.tcx), impl2_def_id.repr(infcx.tcx)); - let param_env = ty::empty_parameter_environment(infcx.tcx); - let mut selcx = SelectionContext::intercrate(infcx, ¶m_env); - let cause = ObligationCause::dummy(); - - // `impl1` provides an implementation of `Foo<X,Y> for Z`. - let impl1_substs = - util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); - let impl1_trait_ref = - (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs); - let impl1_trait_ref = - project::normalize(&mut selcx, cause.clone(), &impl1_trait_ref); - - // Determine whether `impl2` can provide an implementation for those - // same types. - let obligation = Obligation::new(cause, - ty::Binder(ty::TraitPredicate { - trait_ref: Rc::new(impl1_trait_ref.value), - })); - debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); - selcx.evaluate_impl(impl2_def_id, &obligation) && - impl1_trait_ref.obligations.iter().all( - |o| selcx.evaluate_obligation(o)) + let param_env = &ty::empty_parameter_environment(infcx.tcx); + let selcx = &mut SelectionContext::intercrate(infcx, param_env); + infcx.probe(|_| { + overlap(selcx, impl1_def_id, impl2_def_id) || overlap(selcx, impl2_def_id, impl1_def_id) + }) +} + +/// Can the types from impl `a` be used to satisfy impl `b`? +/// (Including all conditions) +fn overlap(selcx: &mut SelectionContext, + a_def_id: ast::DefId, + b_def_id: ast::DefId) + -> bool +{ + let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); + let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); + + // Does `a <: b` hold? If not, no overlap. + if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(), + true, + infer::Misc(DUMMY_SP), + a_trait_ref.to_poly_trait_ref(), + b_trait_ref.to_poly_trait_ref()) { + return false; + } + + // Are any of the obligations unsatisfiable? If so, no overlap. + a_obligations.iter() + .chain(b_obligations.iter()) + .all(|o| selcx.evaluate_obligation(o)) +} + +/// Instantiate fresh variables for all bound parameters of the impl +/// and return the impl trait ref with those variables substituted. +fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, + impl_def_id: ast::DefId) + -> (Rc<ty::TraitRef<'tcx>>, + Vec<PredicateObligation<'tcx>>) +{ + let impl_substs = + &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id); + let impl_trait_ref = + ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); + let impl_trait_ref = + impl_trait_ref.subst(selcx.tcx(), impl_substs); + let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = + project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); + + let predicates = ty::lookup_predicates(selcx.tcx(), impl_def_id); + let predicates = predicates.instantiate(selcx.tcx(), impl_substs); + let Normalized { value: predicates, obligations: normalization_obligations2 } = + project::normalize(selcx, ObligationCause::dummy(), &predicates); + let impl_obligations = + util::predicates_for_generics(selcx.tcx(), ObligationCause::dummy(), 0, &predicates); + + let impl_obligations: Vec<_> = + impl_obligations.into_iter() + .chain(normalization_obligations1.into_iter()) + .chain(normalization_obligations2.into_iter()) + .collect(); + + (impl_trait_ref, impl_obligations) } pub enum OrphanCheckErr<'tcx> { diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 57c9fa7a4d9..a63dcfc24a1 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -28,6 +28,7 @@ use util::ppaux::{Repr, UserString}; pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::suggest_new_overflow_limit; pub use self::coherence::orphan_check; +pub use self::coherence::overlapping_impls; pub use self::coherence::OrphanCheckErr; pub use self::fulfill::{FulfillmentContext, RegionObligation}; pub use self::project::MismatchedProjectionTypes; @@ -270,16 +271,6 @@ pub struct VtableObjectData<'tcx> { pub object_ty: Ty<'tcx>, } -/// True if there exist types that satisfy both of the two given impls. -pub fn overlapping_impls(infcx: &InferCtxt, - impl1_def_id: ast::DefId, - impl2_def_id: ast::DefId) - -> bool -{ - coherence::impl_can_satisfy(infcx, impl1_def_id, impl2_def_id) && - coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id) -} - /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index b2701ae875c..f10f7eb3951 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -20,7 +20,7 @@ use super::supertraits; use super::elaborate_predicates; -use middle::subst::{self, SelfSpace}; +use middle::subst::{self, SelfSpace, TypeSpace}; use middle::traits; use middle::ty::{self, Ty}; use std::rc::Rc; @@ -31,6 +31,10 @@ pub enum ObjectSafetyViolation<'tcx> { /// Self : Sized declared on the trait SizedSelf, + /// Supertrait reference references `Self` an in illegal location + /// (e.g. `trait Foo : Bar<Self>`) + SupertraitSelf, + /// Method has something illegal Method(Rc<ty::Method<'tcx>>, MethodViolationCode), } @@ -57,7 +61,7 @@ pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>, { // Because we query yes/no results frequently, we keep a cache: let cached_result = - tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).map(|&r| r); + tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).cloned(); let result = cached_result.unwrap_or_else(|| { @@ -110,6 +114,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, if trait_has_sized_self(tcx, trait_def_id) { violations.push(ObjectSafetyViolation::SizedSelf); } + if supertraits_reference_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SupertraitSelf); + } debug!("object_safety_violations_for_trait(trait_def_id={}) = {}", trait_def_id.repr(tcx), @@ -118,6 +125,35 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, violations } +fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_def_id: ast::DefId) + -> bool +{ + let trait_def = ty::lookup_trait_def(tcx, trait_def_id); + let trait_ref = trait_def.trait_ref.clone(); + let predicates = ty::predicates_for_trait_ref(tcx, &ty::Binder(trait_ref)); + predicates + .into_iter() + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref data) => { + // In the case of a trait predicate, we can skip the "self" type. + Some(data.def_id()) != tcx.lang_items.phantom_fn() && + data.0.trait_ref.substs.types.get_slice(TypeSpace) + .iter() + .cloned() + .any(is_self) + } + ty::Predicate::Projection(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::Equate(..) => { + false + } + } + }) +} + fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, trait_def_id: ast::DefId) -> bool @@ -138,11 +174,7 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, .any(|predicate| { match predicate { ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - let self_ty = trait_pred.0.self_ty(); - match self_ty.sty { - ty::ty_param(ref data) => data.space == subst::SelfSpace, - _ => false, - } + is_self(trait_pred.0.self_ty()) } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | @@ -295,8 +327,17 @@ impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> { match *self { ObjectSafetyViolation::SizedSelf => format!("SizedSelf"), + ObjectSafetyViolation::SupertraitSelf => + format!("SupertraitSelf"), ObjectSafetyViolation::Method(ref m, code) => format!("Method({},{:?})", m.repr(tcx), code), } } } + +fn is_self<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::ty_param(ref data) => data.space == subst::SelfSpace, + _ => false, + } +} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 027415de998..0e298920841 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -132,6 +132,7 @@ pub enum MethodMatchedData { /// parameters) that would have to be inferred from the impl. #[derive(PartialEq,Eq,Debug,Clone)] enum SelectionCandidate<'tcx> { + PhantomFnCandidate, BuiltinCandidate(ty::BuiltinBound), ParamCandidate(ty::PolyTraitRef<'tcx>), ImplCandidate(ast::DefId), @@ -736,7 +737,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { let cache = self.pick_candidate_cache(); let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_fresh_trait_pred.0.trait_ref).map(|c| (*c).clone()) + hashmap.get(&cache_fresh_trait_pred.0.trait_ref).cloned() } fn insert_candidate_cache(&mut self, @@ -793,8 +794,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> { - // Check for overflow. - let TraitObligationStack { obligation, .. } = *stack; let mut candidates = SelectionCandidateSet { @@ -802,6 +801,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ambiguous: false }; + // Check for the `PhantomFn` trait. This is really just a + // special annotation that is *always* considered to match, no + // matter what the type parameters are etc. + if self.tcx().lang_items.phantom_fn() == Some(obligation.predicate.def_id()) { + candidates.vec.push(PhantomFnCandidate); + return Ok(candidates); + } + // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. @@ -996,7 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let all_bounds = util::transitive_bounds( - self.tcx(), &caller_trait_refs[]); + self.tcx(), &caller_trait_refs[..]); let matching_bounds = all_bounds.filter( @@ -1521,7 +1528,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::substd_enum_variants(self.tcx(), def_id, substs) .iter() .flat_map(|variant| variant.args.iter()) - .map(|&ty| ty) + .cloned() .collect(); nominal(self, bound, def_id, types) } @@ -1629,6 +1636,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { try!(self.confirm_builtin_candidate(obligation, builtin_bound)))) } + PhantomFnCandidate | ErrorCandidate => { Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() })) } @@ -2295,6 +2303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { + PhantomFnCandidate => format!("PhantomFnCandidate"), ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b), ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e3eda02b0a8..e9908397f97 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -68,15 +68,16 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FnvHashMap}; use arena::TypedArena; -use std::borrow::{BorrowFrom, Cow}; +use std::borrow::{Borrow, Cow}; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt; -use std::hash::{Hash, Writer, SipHasher, Hasher}; +use std::hash::{Hash, SipHasher, Hasher}; +#[cfg(stage0)] use std::hash::Writer; use std::mem; use std::ops; use std::rc::Rc; -use std::vec::CowVec; +use std::vec::{CowVec, IntoIter}; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; use syntax::abi; @@ -958,11 +959,18 @@ impl<'tcx> PartialEq for TyS<'tcx> { } impl<'tcx> Eq for TyS<'tcx> {} +#[cfg(stage0)] impl<'tcx, S: Writer + Hasher> Hash<S> for TyS<'tcx> { fn hash(&self, s: &mut S) { (self as *const _).hash(s) } } +#[cfg(not(stage0))] +impl<'tcx> Hash for TyS<'tcx> { + fn hash<H: Hasher>(&self, s: &mut H) { + (self as *const _).hash(s) + } +} pub type Ty<'tcx> = &'tcx TyS<'tcx>; @@ -980,15 +988,22 @@ impl<'tcx> PartialEq for InternedTy<'tcx> { impl<'tcx> Eq for InternedTy<'tcx> {} +#[cfg(stage0)] impl<'tcx, S: Writer + Hasher> Hash<S> for InternedTy<'tcx> { fn hash(&self, s: &mut S) { self.ty.sty.hash(s) } } +#[cfg(not(stage0))] +impl<'tcx> Hash for InternedTy<'tcx> { + fn hash<H: Hasher>(&self, s: &mut H) { + self.ty.sty.hash(s) + } +} -impl<'tcx> BorrowFrom<InternedTy<'tcx>> for sty<'tcx> { - fn borrow_from<'a>(ty: &'a InternedTy<'tcx>) -> &'a sty<'tcx> { - &ty.ty.sty +impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> { + fn borrow<'a>(&'a self) -> &'a sty<'tcx> { + &self.ty.sty } } @@ -2004,6 +2019,40 @@ impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } impl<'tcx> Predicate<'tcx> { + /// Iterates over the types in this predicate. Note that in all + /// cases this is skipping over a binder, so late-bound regions + /// with depth 0 are bound by the predicate. + pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> { + let vec: Vec<_> = match *self { + ty::Predicate::Trait(ref data) => { + data.0.trait_ref.substs.types.as_slice().to_vec() + } + ty::Predicate::Equate(ty::Binder(ref data)) => { + vec![data.0, data.1] + } + ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { + vec![data.0] + } + ty::Predicate::RegionOutlives(..) => { + vec![] + } + ty::Predicate::Projection(ref data) => { + let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice(); + trait_inputs.iter() + .cloned() + .chain(Some(data.0.ty).into_iter()) + .collect() + } + }; + + // The only reason to collect into a vector here is that I was + // too lazy to make the full (somewhat complicated) iterator + // type that would be needed here. But I wanted this fn to + // return an iterator conceptually, rather than a `Vec`, so as + // to be closer to `Ty::walk`. + vec.into_iter() + } + pub fn has_escaping_regions(&self) -> bool { match *self { Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), @@ -2331,7 +2380,7 @@ impl ClosureKind { }; match result { Ok(trait_did) => trait_did, - Err(err) => cx.sess.fatal(&err[]), + Err(err) => cx.sess.fatal(&err[..]), } } } @@ -2665,7 +2714,7 @@ impl FlagComputation { } &ty_tup(ref ts) => { - self.add_tys(&ts[]); + self.add_tys(&ts[..]); } &ty_bare_fn(_, ref f) => { @@ -2836,7 +2885,7 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, def_id: ast::DefId, input_tys: &[Ty<'tcx>], output: Ty<'tcx>) -> Ty<'tcx> { - let input_args = input_tys.iter().map(|ty| *ty).collect(); + let input_args = input_tys.iter().cloned().collect(); mk_bare_fn(cx, Some(def_id), cx.mk_bare_fn(BareFnTy { @@ -2959,6 +3008,13 @@ impl<'tcx> TyS<'tcx> { assert_eq!(r, Some(self)); walker } + + pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> { + match self.sty { + ty::ty_param(ref d) => Some(d.clone()), + _ => None, + } + } } pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F) @@ -3451,7 +3507,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { ty_struct(did, substs) => { let flds = struct_fields(cx, did, substs); let mut res = - TypeContents::union(&flds[], + TypeContents::union(&flds[..], |f| tc_mt(cx, f.mt, cache)); if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) { @@ -3474,14 +3530,14 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } ty_tup(ref tys) => { - TypeContents::union(&tys[], + TypeContents::union(&tys[..], |ty| tc_ty(cx, *ty, cache)) } ty_enum(did, substs) => { let variants = substd_enum_variants(cx, did, substs); let mut res = - TypeContents::union(&variants[], |variant| { + TypeContents::union(&variants[..], |variant| { TypeContents::union(&variant.args[], |arg_ty| { tc_ty(cx, *arg_ty, cache) @@ -3805,7 +3861,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) -> Representability { match ty.sty { ty_tup(ref ts) => { - find_nonrepresentable(cx, sp, seen, ts.iter().map(|ty| *ty)) + find_nonrepresentable(cx, sp, seen, ts.iter().cloned()) } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. @@ -4112,7 +4168,7 @@ pub fn positional_element_ty<'tcx>(cx: &ctxt<'tcx>, variant: Option<ast::DefId>) -> Option<Ty<'tcx>> { match (&ty.sty, variant) { - (&ty_tup(ref v), None) => v.get(i).map(|&t| t), + (&ty_tup(ref v), None) => v.get(i).cloned(), (&ty_struct(def_id, substs), None) => lookup_struct_fields(cx, def_id) @@ -4933,7 +4989,7 @@ pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) { } pub fn provided_source(cx: &ctxt, id: ast::DefId) -> Option<ast::DefId> { - cx.provided_method_sources.borrow().get(&id).map(|x| *x) + cx.provided_method_sources.borrow().get(&id).cloned() } pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) @@ -4944,7 +5000,7 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) match item.node { ItemTrait(_, _, _, ref ms) => { let (_, p) = - ast_util::split_trait_methods(&ms[]); + ast_util::split_trait_methods(&ms[..]); p.iter() .map(|m| { match impl_or_trait_item( @@ -6600,7 +6656,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>, } /// A free variable referred to in a function. -#[derive(Copy, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Freevar { /// The variable being accessed free. pub def: def::Def, @@ -6625,7 +6681,7 @@ pub fn with_freevars<T, F>(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where { match tcx.freevars.borrow().get(&fid) { None => f(&[]), - Some(d) => f(&d[]) + Some(d) => f(&d[..]) } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index ee3fd681a00..60a9ffc7d2e 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -55,7 +55,7 @@ pub fn check_crate(krate: &ast::Crate, pub fn link_name(attrs: &[ast::Attribute]) -> Option<InternedString> { lang_items::extract(attrs).and_then(|name| { - $(if &name[] == stringify!($name) { + $(if &name[..] == stringify!($name) { Some(InternedString::new(stringify!($sym))) } else)* { None |
