Skip to content

Commit

Permalink
Make wf check the bounds of built-in types
Browse files Browse the repository at this point in the history
  • Loading branch information
arielb1 committed May 22, 2015
1 parent c3d60ab commit 6929069
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 33 deletions.
18 changes: 18 additions & 0 deletions src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,24 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
"the return type of a function must have a \
statically known size");
}
ObligationCauseCode::ArgumentType => {
tcx.sess.span_note(
cause_span,
"the type of a function's argument must have a \
statically known size");
}
ObligationCauseCode::TupleElemSized => {
tcx.sess.span_note(
cause_span,
"tuples can only contain elements with a \
statically known size");
}
ObligationCauseCode::VecElemSized => {
tcx.sess.span_note(
cause_span,
"arrays can only contain elements with a \
statically known size");
}
ObligationCauseCode::AssignmentLhsSized => {
tcx.sess.span_note(
cause_span,
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,17 @@ pub enum ObligationCauseCode<'tcx> {
StructInitializerSized, // S { ... } must be Sized
VariableType(ast::NodeId), // Type of each variable must be Sized
ReturnType, // Return type must be Sized
ArgumentType, // Argument type must be Sized
VecElemSized, // Array element must be Sized
TupleElemSized, // Tuple element must be Sized
FieldSized, // Types of fields (other than the last)
// in a struct must be sized.
RepeatVec, // [T,..n] --> T must be Copy

// Captures of variable the given id by a closure (span is the
// span of the closure)
ClosureCapture(ast::NodeId, Span, ty::BuiltinBound),

// Types of fields (other than the last) in a struct must be sized.
FieldSized,

// static items must have `Sync` type
SharedStatic,
Expand Down
1 change: 0 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
.collect();

if let ty::FnConverging(ret_ty) = ret_ty {
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
fn_sig_tys.push(ret_ty);
}

Expand Down
67 changes: 50 additions & 17 deletions src/librustc_typeck/check/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use middle::region;
use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use middle::traits;
use middle::ty::{self, Ty};
use middle::ty::liberate_late_bound_regions;
use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
use util::ppaux::{Repr, UserString};

Expand Down Expand Up @@ -510,10 +509,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
&trait_predicates);

self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(
self.span,
self.fcx.body_id,
traits::ItemObligation(trait_ref.def_id)),
self.cause(traits::ItemObligation(trait_ref.def_id)),
&bounds);

for &ty in trait_ref.substs.types.iter() {
Expand All @@ -532,8 +528,13 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
ty.fold_with(self);
self.binding_count -= 1;
}

fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
traits::ObligationCause::new(self.span, self.fcx.body_id, code)
}
}

// Note: TypeFolder here is used as a visitor.
impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
self.fcx.tcx()
Expand All @@ -543,7 +544,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
self.binding_count += 1;
let value = liberate_late_bound_regions(
let value = ty::liberate_late_bound_regions(
self.fcx.tcx(),
region::DestructionScopeData::new(self.scope),
binder);
Expand All @@ -554,6 +555,24 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
ty::Binder(value)
}


fn fold_fn_sig(&mut self, sig: &ty::FnSig<'tcx>) -> ty::FnSig<'tcx> {
if let ty::FnConverging(ret) = sig.output {
self.fcx.register_builtin_bound(self.fold_ty(ret),
ty::BoundSized,
self.cause(traits::ReturnType));
}

for input in &sig.inputs {
self.fcx.register_builtin_bound(self.fold_ty(input),
ty::BoundSized,
self.cause(traits::ArgumentType));
}

sig.clone()
}


fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
debug!("BoundsChecker t={}",
t.repr(self.tcx()));
Expand All @@ -569,7 +588,23 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
None => { }
}

match t.sty{
match t.sty {
ty::ty_vec(ety, _) => {
self.fcx.register_builtin_bound(self.fold_ty(ety),
ty::BoundSized,
self.cause(traits::VecElemSized));
t
}
ty::ty_tup(ref tys) => {
for ty in tys {
self.fcx.register_builtin_bound(self.fold_ty(ty),
ty::BoundSized,
self.cause(traits::TupleElemSized)
);

}
t
}
ty::ty_struct(type_id, substs) |
ty::ty_enum(type_id, substs) => {
let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id);
Expand All @@ -578,9 +613,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {

if self.binding_count == 0 {
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(self.span,
self.fcx.body_id,
traits::ItemObligation(type_id)),
self.cause(traits::ItemObligation(type_id)),
&bounds);
} else {
// There are two circumstances in which we ignore
Expand All @@ -605,22 +638,22 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
//
// (I believe we should do the same for traits, but
// that will require an RFC. -nmatsakis)
//
// TODO(arielb1): this also seems to be triggered
// when you have something like
// for<'a> Trait<&'a (), &'free1 &'free2 ()>
let bounds = filter_to_trait_obligations(bounds);
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(self.span,
self.fcx.body_id,
traits::ItemObligation(type_id)),
self.cause(traits::ItemObligation(type_id)),
&bounds);
}

self.fold_substs(substs);
t
}
_ => {
super_fold_ty(self, t);
super_fold_ty(self, t)
}
}

t // we're not folding to produce a new type, so just return `t` here
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use std::marker::PhantomData;
use std::ops::Deref;

pub struct Cow<'a, B: ?Sized>(PhantomData<(&'a (),B)>);
pub struct Cow<'a, B: ?Sized+'a>(PhantomData<(&'a (),&'a B)>);

/// Trait for moving into a `Cow`
pub trait IntoCow<'a, B: ?Sized> {
Expand Down
3 changes: 1 addition & 2 deletions src/test/compile-fail/issue-18107.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

pub trait AbstractRenderer {}

fn _create_render(_: &()) ->
AbstractRenderer
fn _create_render(_: &()) -> AbstractRenderer
//~^ ERROR: the trait `core::marker::Sized` is not implemented
{
match 0 {
Expand Down
7 changes: 3 additions & 4 deletions src/test/compile-fail/issue-23041.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
use std::any::Any;
fn main()
{
fn bar(x:i32) ->i32 { 3*x };
let b:Box<Any> = Box::new(bar as fn(_)->_);
b.downcast_ref::<fn(_)->_>();
//~^ ERROR cannot determine a type for this expression: unconstrained type
fn bar(x:&'static i32) -> &'static i32 { x };
let b:Box<Any> = Box::new(bar as fn(&'static _)->&'static _);
b.downcast_ref::<fn(&_)->&_>(); //~ ERROR unconstrained type
}
24 changes: 24 additions & 0 deletions src/test/compile-fail/issue-24957.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2015 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.

pub enum BsonValue {
//~^ ERROR the trait `core::marker::Sized` is not implemented
//~^^ ERROR the trait `core::marker::Sized` is not implemented
A([u8]),
B([BsonValue]),
}

pub fn set_value(_v:&BsonValue)
{
}

fn main()
{
}
1 change: 0 additions & 1 deletion src/test/compile-fail/issue-5883.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ struct Struct {

fn new_struct(r: A+'static)
-> Struct { //~^ ERROR the trait `core::marker::Sized` is not implemented
//~^ ERROR the trait `core::marker::Sized` is not implemented
Struct { r: r }
}

Expand Down
9 changes: 4 additions & 5 deletions src/test/compile-fail/unsized6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

trait T {}

struct T2<U, V: ?Sized>(U, V);

fn f1<X: ?Sized>(x: &X) {
let _: X; // <-- this is OK, no bindings created, no initializer.
let _: (isize, (X, isize)); // same
let _: T2<isize, T2<isize, X>>;
let y: X; //~ERROR the trait `core::marker::Sized` is not implemented
let y: (isize, (X, isize)); //~ERROR the trait `core::marker::Sized` is not implemented
let y: T2<isize, T2<isize, X>>; //~ERROR the trait `core::marker::Sized` is not implemented
}
fn f2<X: ?Sized + T>(x: &X) {
let y: X; //~ERROR the trait `core::marker::Sized` is not implemented
Expand All @@ -34,8 +36,5 @@ fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
let (y, z) = (*x3, 4); //~ERROR the trait `core::marker::Sized` is not implemented
}

fn g1<X: ?Sized>(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented
fn g2<X: ?Sized + T>(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented

pub fn main() {
}
41 changes: 41 additions & 0 deletions src/test/compile-fail/wf-non-well-formed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2015 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.

// Check that we catch attempts to create non-well-formed types

trait Tr {}

fn g1<X: ?Sized>(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented
fn g2<X: ?Sized + Tr>(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented

fn bogus( //~ERROR the trait `core::marker::Sized` is not implemented
_: [u8])
{
loop {}
}

struct S<T: Tr>(T);

fn b1() -> &'static [(u8,fn(&'static [S<()>]))]
{} //~^ ERROR the trait `Tr` is not implemented
fn b2() -> fn([u8])
{} //~^ ERROR the trait `core::marker::Sized` is not implemented
fn b3() -> fn()->[u8]
{} //~^ ERROR the trait `core::marker::Sized` is not implemented
fn b4() -> &'static [[u8]]
{} //~^ ERROR the trait `core::marker::Sized` is not implemented
fn b5() -> &'static [[u8]; 2]
{} //~^ ERROR the trait `core::marker::Sized` is not implemented
fn b6() -> &'static ([u8],)
{} //~^ ERROR the trait `core::marker::Sized` is not implemented
fn b7() -> &'static (u32,[u8],u32)
{} //~^ ERROR the trait `core::marker::Sized` is not implemented

fn main() {}
18 changes: 18 additions & 0 deletions src/test/compile-fail/wf-specific-sized-where-clause.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2015 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.

struct Wrap<'a, T: ?Sized>(&'a (), T);

fn foo<'a, T>(a: for<'s> fn() -> Wrap<'s, T>) where Wrap<'a, T>: Sized {
//~^ ERROR mismatched types
//~^^ ERROR mismatched types
}

fn main() {}

0 comments on commit 6929069

Please sign in to comment.