Skip to content

Commit

Permalink
Auto merge of #27641 - nikomatsakis:soundness-rfc-1214, r=nrc
Browse files Browse the repository at this point in the history
This PR implements the majority of RFC 1214. In particular, it implements:

- the new outlives relation
- comprehensive WF checking

For the most part, new code receives warnings, not errors, though 3 regressions were found via a crater run. 

There are some deviations from RFC 1214. Most notably:

- we still consider implied bounds from fn ret; this intersects other soundness issues that I intend to address in detail in a follow-up RFC. Fixing this without breaking a lot of code probably requires rewriting compare-method somewhat (which is probably a good thing).
- object types do not check trait bounds for fear of encountering `Self`; this was left as an unresolved question in RFC 1214, but ultimately feels inconsistent.

Both of those two issues are highlighted in the tracking issue, #27579. #27579 also includes a testing matrix with new tests that I wrote -- these probably duplicate some existing tests, I tried to check but wasn't quite sure what to look for. I tried to be thorough in testing the WF relation, at least, but would welcome suggestions for missing tests.

r? @nrc (or perhaps someone else?)
  • Loading branch information
bors committed Aug 14, 2015
2 parents 0649b16 + 7f8942c commit e7261f3
Show file tree
Hide file tree
Showing 155 changed files with 4,732 additions and 651 deletions.
2 changes: 1 addition & 1 deletion src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2135,7 +2135,7 @@ impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
/// two `Step` objects.
#[unstable(feature = "step_trait",
reason = "likely to be replaced by finer-grained traits")]
pub trait Step: PartialOrd {
pub trait Step: PartialOrd+Sized {
/// Steps `self` if possible.
fn step(&self, by: &Self) -> Option<Self>;

Expand Down
2 changes: 1 addition & 1 deletion src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub trait Sized {
/// Types that can be "unsized" to a dynamically sized type.
#[unstable(feature = "unsize")]
#[lang="unsize"]
pub trait Unsize<T> {
pub trait Unsize<T: ?Sized> {
// Empty.
}

Expand Down
4 changes: 2 additions & 2 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use char::CharExt;
use cmp::{Eq, PartialOrd};
use fmt;
use intrinsics;
use marker::Copy;
use marker::{Copy, Sized};
use mem::size_of;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
Expand Down Expand Up @@ -1263,7 +1263,7 @@ pub enum FpCategory {
#[doc(hidden)]
#[unstable(feature = "core_float",
reason = "stable interface is via `impl f{32,64}` in later crates")]
pub trait Float {
pub trait Float: Sized {
/// Returns the NaN value.
fn nan() -> Self;
/// Returns the infinite value.
Expand Down
3 changes: 2 additions & 1 deletion src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use default::Default;
use fmt;
use iter::ExactSizeIterator;
use iter::{Map, Iterator, DoubleEndedIterator};
use marker::Sized;
use mem;
use ops::{Fn, FnMut, FnOnce};
use option::Option::{self, None, Some};
Expand All @@ -37,7 +38,7 @@ pub mod pattern;
/// A trait to abstract the idea of creating a new instance of a type from a
/// string.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromStr {
pub trait FromStr: Sized {
/// The associated error which can be returned from parsing.
#[stable(feature = "rust1", since = "1.0.0")]
type Err;
Expand Down
2 changes: 1 addition & 1 deletion src/libgraphviz/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ pub type Edges<'a,E> = Cow<'a,[E]>;
/// `Cow<[T]>` to leave implementers the freedom to create
/// entirely new vectors or to pass back slices into internally owned
/// vectors.
pub trait GraphWalk<'a, N, E> {
pub trait GraphWalk<'a, N: Clone, E: Clone> {
/// Returns all the nodes in this graph.
fn nodes(&'a self) -> Nodes<'a, N>;
/// Returns all of the edges in this graph.
Expand Down
3 changes: 2 additions & 1 deletion src/librand/distributions/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

// this is surprisingly complicated to be both generic & correct

use core::marker::Sized;
use Rng;
use distributions::{Sample, IndependentSample};

Expand Down Expand Up @@ -57,7 +58,7 @@ impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
#[doc(hidden)]
pub trait SampleRange {
pub trait SampleRange: Sized {
/// Construct the `Range` object that `sample_range`
/// requires. This should not ever be called directly, only via
/// `Range::new`, which will check that `low < high`, so this
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ pub mod middle {
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
pub mod outlives;
pub mod pat_util;
pub mod privacy;
pub mod reachable;
Expand All @@ -143,6 +144,7 @@ pub mod middle {
pub mod ty_match;
pub mod ty_relate;
pub mod ty_walk;
pub mod wf;
pub mod weak_lang_items;
}

Expand Down
6 changes: 6 additions & 0 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,12 @@ fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>,
'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv),
parse_region_(st, conv))).to_predicate(),
'p' => ty::Binder(parse_projection_predicate_(st, conv)).to_predicate(),
'w' => ty::Predicate::WellFormed(parse_ty_(st, conv)),
'O' => {
let def_id = parse_def_(st, NominalType, conv);
assert_eq!(next(st), '|');
ty::Predicate::ObjectSafe(def_id)
}
c => panic!("Encountered invalid character in metadata: {}", c)
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,13 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder,
mywrite!(w, "p");
enc_projection_predicate(w, cx, data)
}
ty::Predicate::WellFormed(data) => {
mywrite!(w, "w");
enc_ty(w, cx, data);
}
ty::Predicate::ObjectSafe(trait_def_id) => {
mywrite!(w, "O{}|", (cx.ds)(trait_def_id));
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
}
}

trait doc_decoder_helpers {
trait doc_decoder_helpers: Sized {
fn as_int(&self) -> isize;
fn opt_child(&self, tag: c::astencode_tag) -> Option<Self>;
}
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl OverloadedCallType {
// supplies types from the tree. After type checking is complete, you
// can just use the tcx as the typer.

pub struct ExprUseVisitor<'d,'t,'a: 't, 'tcx:'a> {
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
typer: &'t infer::InferCtxt<'a, 'tcx>,
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
delegate: &'d mut (Delegate<'tcx>+'d),
Expand Down Expand Up @@ -273,7 +273,8 @@ enum PassArgs {
impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
pub fn new(delegate: &'d mut Delegate<'tcx>,
typer: &'t infer::InferCtxt<'a, 'tcx>)
-> ExprUseVisitor<'d,'t,'a, 'tcx> {
-> ExprUseVisitor<'d,'t,'a,'tcx>
{
ExprUseVisitor {
typer: typer,
mc: mc::MemCategorizationContext::new(typer),
Expand Down
23 changes: 13 additions & 10 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

//! This file defines

use middle::implicator::Implication;
use middle::wf::ImpliedBound;
use middle::ty::{self, FreeRegion};
use util::common::can_reach;
use util::nodemap::{FnvHashMap, FnvHashSet};
Expand All @@ -30,18 +30,19 @@ impl FreeRegionMap {
FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() }
}

pub fn relate_free_regions_from_implications<'tcx>(&mut self,
implications: &[Implication<'tcx>])
pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
implied_bounds: &[ImpliedBound<'tcx>])
{
for implication in implications {
debug!("implication: {:?}", implication);
match *implication {
Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
debug!("relate_free_regions_from_implied_bounds()");
for implied_bound in implied_bounds {
debug!("implied bound: {:?}", implied_bound);
match *implied_bound {
ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => {
self.relate_free_regions(free_a, free_b);
}
Implication::RegionSubRegion(..) |
Implication::RegionSubGeneric(..) |
Implication::Predicate(..) => {
ImpliedBound::RegionSubRegion(..) |
ImpliedBound::RegionSubParam(..) |
ImpliedBound::RegionSubProjection(..) => {
}
}
}
Expand All @@ -56,6 +57,8 @@ impl FreeRegionMap {
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::TypeOutlives(..) => {
// No region bounds here
}
Expand Down
56 changes: 5 additions & 51 deletions src/librustc/middle/implicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use middle::infer::{InferCtxt, GenericKind};
use middle::subst::Substs;
use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, ToPredicate, Ty};
use middle::ty::{self, RegionEscape, ToPredicate, Ty};
use middle::ty_fold::{TypeFoldable, TypeFolder};

use syntax::ast;
Expand Down Expand Up @@ -278,9 +278,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {

for predicate in predicates.predicates.as_slice() {
match *predicate {
ty::Predicate::Trait(ref data) => {
self.accumulate_from_assoc_types_transitive(data);
}
ty::Predicate::Trait(..) => { }
ty::Predicate::Equate(..) => { }
ty::Predicate::Projection(..) => { }
ty::Predicate::RegionOutlives(ref data) => {
Expand All @@ -301,6 +299,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
}
}
}
ty::Predicate::ObjectSafe(_) |
ty::Predicate::WellFormed(_) => {
}
}
}

Expand Down Expand Up @@ -349,53 +350,6 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
}
}

/// Given that there is a requirement that `Foo<X> : 'a`, where
/// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
/// this code finds all the associated types defined in
/// `SomeTrait` (and supertraits) and adds a requirement that `<X
/// as SomeTrait>::N : 'a` (where `N` is some associated type
/// defined in `SomeTrait`). This rule only applies to
/// trait-bounds that are not higher-ranked, because we cannot
/// project out of a HRTB. This rule helps code using associated
/// types to compile, see Issue #22246 for an example.
fn accumulate_from_assoc_types_transitive(&mut self,
data: &ty::PolyTraitPredicate<'tcx>)
{
debug!("accumulate_from_assoc_types_transitive({:?})",
data);

for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
match self.tcx().no_late_bound_regions(&poly_trait_ref) {
Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
None => { }
}
}
}

fn accumulate_from_assoc_types(&mut self,
trait_ref: ty::TraitRef<'tcx>)
{
debug!("accumulate_from_assoc_types({:?})",
trait_ref);

let trait_def_id = trait_ref.def_id;
let trait_def = self.tcx().lookup_trait_def(trait_def_id);
let assoc_type_projections: Vec<_> =
trait_def.associated_type_names
.iter()
.map(|&name| self.tcx().mk_projection(trait_ref.clone(), name))
.collect();
debug!("accumulate_from_assoc_types: assoc_type_projections={:?}",
assoc_type_projections);
let tys = match self.fully_normalize(&assoc_type_projections) {
Ok(tys) => { tys }
Err(ErrorReported) => { return; }
};
for ty in tys {
self.accumulate_from_ty(ty);
}
}

fn accumulate_from_object_ty(&mut self,
ty: Ty<'tcx>,
region_bound: ty::Region,
Expand Down
Loading

0 comments on commit e7261f3

Please sign in to comment.