auto merge of #17466 : nikomatsakis/rust/oibt, r=pcwalton
Moves the vast majority of builtin bound checking out of type contents and into the trait system. This is a preliminary step for a lot of follow-on work: - opt-in builtin types, obviously - generalized where clauses, because TypeContents has this notion that a type parameter has a single set of builtin kinds, but with where clauses it depends on context - generalized coherence, because this adds support for recursive trait selection Unfortunately I wasn't able to completely remove Type Contents from the front-end checking in this PR. It's still used by EUV to decide what gets moved and what doesn't. r? @pcwalton
This commit is contained in:
commit
2550243b41
47 changed files with 1194 additions and 1112 deletions
|
@ -59,6 +59,7 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
|||
TOOLS := compiletest rustdoc rustc
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_libc := core
|
||||
DEPS_rlibc := core
|
||||
DEPS_unicode := core
|
||||
DEPS_alloc := core libc native:jemalloc
|
||||
|
|
|
@ -466,7 +466,7 @@ fn start(_argc: int, _argv: *const *const u8) -> int {
|
|||
// provided by libstd.
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "sized"] trait Sized { }
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
# // fn main() {} tricked you, rustdoc!
|
||||
```
|
||||
|
||||
|
@ -489,32 +489,28 @@ pub extern fn main(argc: int, argv: *const *const u8) -> int {
|
|||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "sized"] trait Sized { }
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
# // fn main() {} tricked you, rustdoc!
|
||||
```
|
||||
|
||||
|
||||
The compiler currently makes a few assumptions about symbols which are available
|
||||
in the executable to call. Normally these functions are provided by the standard
|
||||
xlibrary, but without it you must define your own.
|
||||
library, but without it you must define your own.
|
||||
|
||||
The first of these two functions, `stack_exhausted`, is invoked whenever stack
|
||||
The first of these three functions, `stack_exhausted`, is invoked whenever stack
|
||||
overflow is detected. This function has a number of restrictions about how it
|
||||
can be called and what it must do, but if the stack limit register is not being
|
||||
maintained then a task always has an "infinite stack" and this function
|
||||
shouldn't get triggered.
|
||||
|
||||
The second of these two functions, `eh_personality`, is used by the failure
|
||||
mechanisms of the compiler. This is often mapped to GCC's personality function
|
||||
(see the [libstd implementation](std/rt/unwind/index.html) for more
|
||||
information), but crates which do not trigger failure can be assured that this
|
||||
function is never called.
|
||||
|
||||
The final item in the example is a trait called `Sized`. This a trait
|
||||
that represents data of a known static size: it is integral to the
|
||||
Rust type system, and so the compiler expects the standard library to
|
||||
provide it. Since you are not using the standard library, you have to
|
||||
provide it yourself.
|
||||
The second of these three functions, `eh_personality`, is used by the
|
||||
failure mechanisms of the compiler. This is often mapped to GCC's
|
||||
personality function (see the
|
||||
[libstd implementation](std/rt/unwind/index.html) for more
|
||||
information), but crates which do not trigger failure can be assured
|
||||
that this function is never called. The final function, `fail_fmt`, is
|
||||
also used by the failure mechanisms of the compiler.
|
||||
|
||||
## Using libcore
|
||||
|
||||
|
@ -694,7 +690,7 @@ fn main(argc: int, argv: *const *const u8) -> int {
|
|||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "sized"] trait Sized {}
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
```
|
||||
|
||||
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
|
||||
|
|
|
@ -25,19 +25,19 @@ pub use self::Sync as Share;
|
|||
|
||||
/// Types able to be transferred across task boundaries.
|
||||
#[lang="send"]
|
||||
pub trait Send {
|
||||
pub trait Send for Sized? {
|
||||
// empty.
|
||||
}
|
||||
|
||||
/// Types with a constant size known at compile-time.
|
||||
#[lang="sized"]
|
||||
pub trait Sized {
|
||||
pub trait Sized for Sized? {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||
#[lang="copy"]
|
||||
pub trait Copy {
|
||||
pub trait Copy for Sized? {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub trait Copy {
|
|||
/// reference; not doing this is undefined behaviour (for example,
|
||||
/// `transmute`-ing from `&T` to `&mut T` is illegal).
|
||||
#[lang="sync"]
|
||||
pub trait Sync {
|
||||
pub trait Sync for Sized? {
|
||||
// Empty
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#![allow(missing_doc)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
#[cfg(test)] extern crate std;
|
||||
#[cfg(test)] extern crate test;
|
||||
#[cfg(test)] extern crate native;
|
||||
|
|
|
@ -58,8 +58,6 @@ register_diagnostics!(
|
|||
E0039,
|
||||
E0040,
|
||||
E0041,
|
||||
E0042,
|
||||
E0043,
|
||||
E0044,
|
||||
E0045,
|
||||
E0046,
|
||||
|
@ -92,7 +90,6 @@ register_diagnostics!(
|
|||
E0075,
|
||||
E0076,
|
||||
E0077,
|
||||
E0078,
|
||||
E0079,
|
||||
E0080,
|
||||
E0081,
|
||||
|
@ -130,7 +127,6 @@ register_diagnostics!(
|
|||
E0121,
|
||||
E0122,
|
||||
E0124,
|
||||
E0125,
|
||||
E0126,
|
||||
E0127,
|
||||
E0128,
|
||||
|
@ -147,12 +143,6 @@ register_diagnostics!(
|
|||
E0139,
|
||||
E0140,
|
||||
E0141,
|
||||
E0143,
|
||||
E0144,
|
||||
E0145,
|
||||
E0146,
|
||||
E0148,
|
||||
E0151,
|
||||
E0152,
|
||||
E0153,
|
||||
E0154,
|
||||
|
|
|
@ -17,7 +17,7 @@ use lint;
|
|||
use llvm::{ContextRef, ModuleRef};
|
||||
use metadata::common::LinkMeta;
|
||||
use metadata::creader;
|
||||
use middle::{trans, stability, kind, ty, typeck, reachable};
|
||||
use middle::{trans, stability, ty, typeck, reachable};
|
||||
use middle::dependency_format;
|
||||
use middle;
|
||||
use plugin::load::Plugins;
|
||||
|
@ -462,8 +462,12 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
|||
time(time_passes, "rvalue checking", (), |_|
|
||||
middle::check_rvalues::check_crate(&ty_cx, krate));
|
||||
|
||||
time(time_passes, "kind checking", (), |_|
|
||||
kind::check_crate(&ty_cx));
|
||||
// Avoid overwhelming user with errors if type checking failed.
|
||||
// I'm not sure how helpful this is, to be honest, but it avoids a
|
||||
// lot of annoying errors in the compile-fail tests (basically,
|
||||
// lint warnings and so on -- kindck used to do this abort, but
|
||||
// kindck is gone now). -nmatsakis
|
||||
ty_cx.sess.abort_if_errors();
|
||||
|
||||
let reachable_map =
|
||||
time(time_passes, "reachability checking", (), |_|
|
||||
|
|
|
@ -95,7 +95,6 @@ pub mod middle {
|
|||
pub mod expr_use_visitor;
|
||||
pub mod graph;
|
||||
pub mod intrinsicck;
|
||||
pub mod kind;
|
||||
pub mod lang_items;
|
||||
pub mod liveness;
|
||||
pub mod mem_categorization;
|
||||
|
|
|
@ -1,404 +0,0 @@
|
|||
// Copyright 2012-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.
|
||||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::ty_fold;
|
||||
use util::ppaux::{ty_to_string};
|
||||
use util::ppaux::UserString;
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::print::pprust::{expr_to_string, ident_to_string};
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
|
||||
// Kind analysis pass. This pass does some ad-hoc checks that are more
|
||||
// convenient to do after type checking is complete and all checks are
|
||||
// known. These are generally related to the builtin bounds `Copy` and
|
||||
// `Sized`. Note that many of the builtin bound properties that used
|
||||
// to be checked here are actually checked by trait checking these
|
||||
// days.
|
||||
|
||||
pub struct Context<'a,'tcx:'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &Expr) {
|
||||
check_expr(self, ex);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: visit::FnKind, fd: &'v FnDecl,
|
||||
b: &'v Block, s: Span, n: NodeId) {
|
||||
check_fn(self, fk, fd, b, s, n);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &Ty) {
|
||||
check_ty(self, t);
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &Item) {
|
||||
check_item(self, i);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &Pat) {
|
||||
check_pat(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(tcx: &ty::ctxt) {
|
||||
let mut ctx = Context {
|
||||
tcx: tcx,
|
||||
};
|
||||
visit::walk_crate(&mut ctx, tcx.map.krate());
|
||||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
struct EmptySubstsFolder<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>
|
||||
}
|
||||
impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for EmptySubstsFolder<'a, 'tcx> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs {
|
||||
subst::Substs::empty()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_struct_safe_for_destructor(cx: &mut Context,
|
||||
span: Span,
|
||||
struct_did: DefId) {
|
||||
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
|
||||
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
|
||||
&& !struct_tpt.generics.has_region_params(subst::TypeSpace) {
|
||||
let mut folder = EmptySubstsFolder { tcx: cx.tcx };
|
||||
if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) {
|
||||
span_err!(cx.tcx.sess, span, E0125,
|
||||
"cannot implement a destructor on a \
|
||||
structure or enumeration that does not satisfy Send");
|
||||
span_note!(cx.tcx.sess, span,
|
||||
"use \"#[unsafe_destructor]\" on the implementation \
|
||||
to force the compiler to allow this");
|
||||
}
|
||||
} else {
|
||||
span_err!(cx.tcx.sess, span, E0141,
|
||||
"cannot implement a destructor on a structure \
|
||||
with type parameters");
|
||||
span_note!(cx.tcx.sess, span,
|
||||
"use \"#[unsafe_destructor]\" on the implementation \
|
||||
to force the compiler to allow this");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) {
|
||||
let ast_trait_def = *cx.tcx.def_map.borrow()
|
||||
.find(&trait_ref.ref_id)
|
||||
.expect("trait ref not in def map!");
|
||||
let trait_def_id = ast_trait_def.def_id();
|
||||
|
||||
// If this is a destructor, check kinds.
|
||||
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) &&
|
||||
!attr::contains_name(it.attrs.as_slice(), "unsafe_destructor")
|
||||
{
|
||||
match self_type.node {
|
||||
TyPath(_, ref bounds, path_node_id) => {
|
||||
assert!(bounds.is_none());
|
||||
let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id);
|
||||
let struct_did = struct_def.def_id();
|
||||
check_struct_safe_for_destructor(cx, self_type.span, struct_did);
|
||||
}
|
||||
_ => {
|
||||
cx.tcx.sess.span_bug(self_type.span,
|
||||
"the self type for the Drop trait impl is not a path");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(cx: &mut Context, item: &Item) {
|
||||
match item.node {
|
||||
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
|
||||
check_impl_of_trait(cx, item, trait_ref, &**self_type);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_item(cx, item)
|
||||
}
|
||||
|
||||
// Yields the appropriate function to check the kind of closed over
|
||||
// variables. `id` is the NodeId for some expression that creates the
|
||||
// closure.
|
||||
fn with_appropriate_checker(cx: &Context,
|
||||
id: NodeId,
|
||||
fn_span: Span,
|
||||
b: |checker: |&Context, &ty::Freevar||) {
|
||||
fn check_for_uniq(cx: &Context,
|
||||
fn_span: Span,
|
||||
fv: &ty::Freevar,
|
||||
bounds: ty::BuiltinBounds) {
|
||||
// all captured data must be owned, regardless of whether it is
|
||||
// moved in or copied in.
|
||||
let id = fv.def.def_id().node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
|
||||
check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None);
|
||||
}
|
||||
|
||||
fn check_for_block(cx: &Context,
|
||||
fn_span: Span,
|
||||
fn_id: NodeId,
|
||||
fv: &ty::Freevar,
|
||||
bounds: ty::BuiltinBounds) {
|
||||
let id = fv.def.def_id().node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id };
|
||||
let upvar_borrow = cx.tcx.upvar_borrow(upvar_id);
|
||||
let implicit_borrowed_type =
|
||||
ty::mk_rptr(cx.tcx,
|
||||
upvar_borrow.region,
|
||||
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
||||
ty: var_t });
|
||||
check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type,
|
||||
bounds, Some(var_t));
|
||||
}
|
||||
|
||||
fn check_for_bare(cx: &Context, fv: &ty::Freevar) {
|
||||
span_err!(cx.tcx.sess, fv.span, E0143,
|
||||
"can't capture dynamic environment in a fn item; \
|
||||
use the || {} closure form instead", "{ ... }");
|
||||
} // same check is done in resolve.rs, but shouldn't be done
|
||||
|
||||
let fty = ty::node_id_to_type(cx.tcx, id);
|
||||
match ty::get(fty).sty {
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::UniqTraitStore,
|
||||
bounds: bounds,
|
||||
..
|
||||
}) => {
|
||||
b(|cx, fv| check_for_uniq(cx, fn_span, fv,
|
||||
bounds.builtin_bounds))
|
||||
}
|
||||
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(..), bounds, ..
|
||||
}) => {
|
||||
b(|cx, fv| check_for_block(cx, fn_span, id, fv,
|
||||
bounds.builtin_bounds))
|
||||
}
|
||||
|
||||
ty::ty_bare_fn(_) => {
|
||||
b(check_for_bare)
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(..) => {}
|
||||
|
||||
ref s => {
|
||||
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
|
||||
{:?}",
|
||||
s).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the free variables used in a shared/sendable closure conform
|
||||
// to the copy/move kind bounds. Then recursively check the function body.
|
||||
fn check_fn(
|
||||
cx: &mut Context,
|
||||
fk: visit::FnKind,
|
||||
decl: &FnDecl,
|
||||
body: &Block,
|
||||
sp: Span,
|
||||
fn_id: NodeId) {
|
||||
|
||||
// <Check kinds on free variables:
|
||||
with_appropriate_checker(cx, fn_id, sp, |chk| {
|
||||
ty::with_freevars(cx.tcx, fn_id, |freevars| {
|
||||
for fv in freevars.iter() {
|
||||
chk(cx, fv);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
match fk {
|
||||
visit::FkFnBlock(..) => {
|
||||
visit::walk_fn(cx, fk, decl, body, sp)
|
||||
}
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
visit::walk_fn(cx, fk, decl, body, sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
debug!("kind::check_expr({})", expr_to_string(e));
|
||||
|
||||
match e.node {
|
||||
ExprRepeat(ref element, ref count_expr) => {
|
||||
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
|
||||
if count > 1 {
|
||||
let element_ty = ty::expr_ty(cx.tcx, &**element);
|
||||
check_copy(cx, element_ty, element.span,
|
||||
"repeated element will be copied");
|
||||
}
|
||||
}
|
||||
ExprAssign(ref lhs, _) |
|
||||
ExprAssignOp(_, ref lhs, _) => {
|
||||
let lhs_ty = ty::expr_ty(cx.tcx, &**lhs);
|
||||
if !ty::type_is_sized(cx.tcx, lhs_ty) {
|
||||
cx.tcx.sess.span_err(lhs.span, "dynamically sized type on lhs of assignment");
|
||||
}
|
||||
}
|
||||
ExprStruct(..) => {
|
||||
let e_ty = ty::expr_ty(cx.tcx, e);
|
||||
if !ty::type_is_sized(cx.tcx, e_ty) {
|
||||
cx.tcx.sess.span_err(e.span, "trying to initialise a dynamically sized struct");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_expr(cx, e);
|
||||
}
|
||||
|
||||
fn check_ty(cx: &mut Context, aty: &Ty) {
|
||||
match aty.node {
|
||||
TyPath(_, _, id) => {
|
||||
match cx.tcx.item_substs.borrow().find(&id) {
|
||||
None => {}
|
||||
Some(ref item_substs) => {
|
||||
let def_map = cx.tcx.def_map.borrow();
|
||||
let did = def_map.get_copy(&id).def_id();
|
||||
let generics = ty::lookup_item_type(cx.tcx, did).generics;
|
||||
for def in generics.types.iter() {
|
||||
let ty = *item_substs.substs.types.get(def.space,
|
||||
def.index);
|
||||
check_typaram_bounds(cx, aty.span, ty, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_ty(cx, aty);
|
||||
}
|
||||
|
||||
// Calls "any_missing" if any bounds were missing.
|
||||
pub fn check_builtin_bounds(cx: &Context,
|
||||
ty: ty::t,
|
||||
bounds: ty::BuiltinBounds,
|
||||
any_missing: |ty::BuiltinBounds|) {
|
||||
let kind = ty::type_contents(cx.tcx, ty);
|
||||
let mut missing = ty::empty_builtin_bounds();
|
||||
for bound in bounds.iter() {
|
||||
if !kind.meets_builtin_bound(cx.tcx, bound) {
|
||||
missing.add(bound);
|
||||
}
|
||||
}
|
||||
if !missing.is_empty() {
|
||||
any_missing(missing);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_typaram_bounds(cx: &Context,
|
||||
sp: Span,
|
||||
ty: ty::t,
|
||||
type_param_def: &ty::TypeParameterDef) {
|
||||
check_builtin_bounds(cx,
|
||||
ty,
|
||||
type_param_def.bounds.builtin_bounds,
|
||||
|missing| {
|
||||
span_err!(cx.tcx.sess, sp, E0144,
|
||||
"instantiating a type parameter with an incompatible type \
|
||||
`{}`, which does not fulfill `{}`",
|
||||
ty_to_string(cx.tcx, ty),
|
||||
missing.user_string(cx.tcx));
|
||||
});
|
||||
}
|
||||
|
||||
pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t,
|
||||
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
|
||||
{
|
||||
check_builtin_bounds(cx, ty, bounds, |missing| {
|
||||
// Will be Some if the freevar is implicitly borrowed (stack closure).
|
||||
// Emit a less mysterious error message in this case.
|
||||
match referenced_ty {
|
||||
Some(rty) => {
|
||||
span_err!(cx.tcx.sess, sp, E0145,
|
||||
"cannot implicitly borrow variable of type `{}` in a \
|
||||
bounded stack closure (implicit reference does not fulfill `{}`)",
|
||||
ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
|
||||
}
|
||||
None => {
|
||||
span_err!(cx.tcx.sess, sp, E0146,
|
||||
"cannot capture variable of type `{}`, which does \
|
||||
not fulfill `{}`, in a bounded closure",
|
||||
ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
|
||||
}
|
||||
}
|
||||
span_note!(cx.tcx.sess, fn_span,
|
||||
"this closure's environment must satisfy `{}`",
|
||||
bounds.user_string(cx.tcx));
|
||||
});
|
||||
}
|
||||
|
||||
fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
|
||||
debug!("type_contents({})={}",
|
||||
ty_to_string(cx.tcx, ty),
|
||||
ty::type_contents(cx.tcx, ty).to_string());
|
||||
if ty::type_moves_by_default(cx.tcx, ty) {
|
||||
span_err!(cx.tcx.sess, sp, E0148,
|
||||
"copying a value of non-copyable type `{}`",
|
||||
ty_to_string(cx.tcx, ty));
|
||||
span_note!(cx.tcx.sess, sp, "{}", reason.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
|
||||
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
|
||||
if !ty::type_is_sized(tcx, ty) {
|
||||
span_err!(tcx.sess, sp, E0151,
|
||||
"variable `{}` has dynamically sized type `{}`",
|
||||
name, ty_to_string(tcx, ty));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that any variables in a pattern have types with statically known size.
|
||||
fn check_pat(cx: &mut Context, pat: &Pat) {
|
||||
let var_name = match pat.node {
|
||||
PatWild(PatWildSingle) => Some("_".to_string()),
|
||||
PatIdent(_, ref path1, _) => Some(ident_to_string(&path1.node).to_string()),
|
||||
_ => None
|
||||
};
|
||||
|
||||
match var_name {
|
||||
Some(name) => {
|
||||
let types = cx.tcx.node_types.borrow();
|
||||
let ty = types.find(&(pat.id as uint));
|
||||
match ty {
|
||||
Some(ty) => {
|
||||
debug!("kind: checking sized-ness of variable {}: {}",
|
||||
name, ty_to_string(cx.tcx, *ty));
|
||||
check_sized(cx.tcx, *ty, name, pat.span);
|
||||
}
|
||||
None => {} // extern fn args
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
visit::walk_pat(cx, pat);
|
||||
}
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
/*! See `doc.rs` for high-level documentation */
|
||||
|
||||
use super::DUMMY_CAUSE;
|
||||
use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
|
||||
use super::{evaluate_impl};
|
||||
use super::ObligationCause;
|
||||
use super::util;
|
||||
|
||||
use middle::subst;
|
||||
|
@ -21,7 +21,6 @@ use middle::ty;
|
|||
use middle::typeck::infer::InferCtxt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use util::nodemap::DefIdMap;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub fn impl_can_satisfy(infcx: &InferCtxt,
|
||||
|
@ -40,8 +39,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
|||
// Determine whether `impl2` can provide an implementation for those
|
||||
// same types.
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let unboxed_closures = DefIdMap::new();
|
||||
match evaluate_impl(infcx, ¶m_env, &unboxed_closures, DUMMY_CAUSE,
|
||||
match evaluate_impl(infcx, ¶m_env, infcx.tcx, ObligationCause::dummy(),
|
||||
impl2_def_id, impl1_self_ty) {
|
||||
EvaluatedToMatch | EvaluatedToAmbiguity => true,
|
||||
EvaluatedToUnmatch => false,
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::{InferCtxt, skolemize};
|
||||
use util::nodemap::DefIdMap;
|
||||
use middle::typeck::infer::InferCtxt;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use super::CodeAmbiguity;
|
||||
|
@ -18,7 +18,6 @@ use super::Obligation;
|
|||
use super::FulfillmentError;
|
||||
use super::CodeSelectionError;
|
||||
use super::select::SelectionContext;
|
||||
use super::Unimplemented;
|
||||
|
||||
/**
|
||||
* The fulfillment context is used to drive trait resolution. It
|
||||
|
@ -36,17 +35,12 @@ pub struct FulfillmentContext {
|
|||
// A list of all obligations that have been registered with this
|
||||
// fulfillment context.
|
||||
trait_obligations: Vec<Obligation>,
|
||||
|
||||
// For semi-hacky reasons (see FIXME below) we keep the builtin
|
||||
// trait obligations segregated.
|
||||
builtin_obligations: Vec<Obligation>,
|
||||
}
|
||||
|
||||
impl FulfillmentContext {
|
||||
pub fn new() -> FulfillmentContext {
|
||||
FulfillmentContext {
|
||||
trait_obligations: Vec::new(),
|
||||
builtin_obligations: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,24 +49,16 @@ impl FulfillmentContext {
|
|||
obligation: Obligation)
|
||||
{
|
||||
debug!("register_obligation({})", obligation.repr(tcx));
|
||||
match tcx.lang_items.to_builtin_kind(obligation.trait_ref.def_id) {
|
||||
Some(_) => {
|
||||
self.builtin_obligations.push(obligation);
|
||||
}
|
||||
None => {
|
||||
self.trait_obligations.push(obligation);
|
||||
}
|
||||
}
|
||||
self.trait_obligations.push(obligation);
|
||||
}
|
||||
|
||||
pub fn select_all_or_error(&mut self,
|
||||
infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
|
||||
-> Result<(),Vec<FulfillmentError>>
|
||||
pub fn select_all_or_error<'a,'tcx>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
typer: &Typer<'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError>>
|
||||
{
|
||||
try!(self.select_where_possible(infcx, param_env,
|
||||
unboxed_closures));
|
||||
try!(self.select_where_possible(infcx, param_env, typer));
|
||||
|
||||
// Anything left is ambiguous.
|
||||
let errors: Vec<FulfillmentError> =
|
||||
|
@ -88,15 +74,14 @@ impl FulfillmentContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn select_where_possible(&mut self,
|
||||
infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
|
||||
-> Result<(),Vec<FulfillmentError>>
|
||||
pub fn select_where_possible<'a,'tcx>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
typer: &Typer<'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError>>
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
let selcx = SelectionContext::new(infcx, param_env,
|
||||
unboxed_closures);
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
|
||||
debug!("select_where_possible({} obligations) start",
|
||||
self.trait_obligations.len());
|
||||
|
@ -158,92 +143,4 @@ impl FulfillmentContext {
|
|||
Err(errors)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_bound_obligations(
|
||||
&self,
|
||||
infcx: &InferCtxt)
|
||||
-> Result<(),Vec<FulfillmentError>>
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
let mut errors = Vec::new();
|
||||
debug!("check_builtin_bound_obligations");
|
||||
for obligation in self.builtin_obligations.iter() {
|
||||
debug!("obligation={}", obligation.repr(tcx));
|
||||
|
||||
let def_id = obligation.trait_ref.def_id;
|
||||
let bound = match tcx.lang_items.to_builtin_kind(def_id) {
|
||||
Some(bound) => { bound }
|
||||
None => { continue; }
|
||||
};
|
||||
|
||||
let unskol_self_ty = obligation.self_ty();
|
||||
|
||||
// Skolemize the self-type so that it no longer contains
|
||||
// inference variables. Note that this also replaces
|
||||
// regions with 'static. You might think that this is not
|
||||
// ok, because checking whether something is `Send`
|
||||
// implies checking whether it is 'static: that's true,
|
||||
// but in fact the region bound is fed into region
|
||||
// inference separately and enforced there (and that has
|
||||
// even already been done before this code executes,
|
||||
// generally speaking).
|
||||
let self_ty = skolemize(infcx, unskol_self_ty);
|
||||
|
||||
debug!("bound={} self_ty={}", bound, self_ty.repr(tcx));
|
||||
if ty::type_is_error(self_ty) {
|
||||
// Indicates an error that was/will-be
|
||||
// reported elsewhere.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine if builtin bound is met.
|
||||
let tc = ty::type_contents(tcx, self_ty);
|
||||
debug!("tc={}", tc);
|
||||
let met = match bound {
|
||||
ty::BoundSend => tc.is_sendable(tcx),
|
||||
ty::BoundSized => tc.is_sized(tcx),
|
||||
ty::BoundCopy => tc.is_copy(tcx),
|
||||
ty::BoundSync => tc.is_sync(tcx),
|
||||
};
|
||||
|
||||
if met {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME -- This is kind of a hack: it requently happens
|
||||
// that some earlier error prevents types from being fully
|
||||
// inferred, and then we get a bunch of uninteresting
|
||||
// errors saying something like "<generic #0> doesn't
|
||||
// implement Sized". It may even be true that we could
|
||||
// just skip over all checks where the self-ty is an
|
||||
// inference variable, but I was afraid that there might
|
||||
// be an inference variable created, registered as an
|
||||
// obligation, and then never forced by writeback, and
|
||||
// hence by skipping here we'd be ignoring the fact that
|
||||
// we don't KNOW the type works out. Though even that
|
||||
// would probably be harmless, given that we're only
|
||||
// talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check
|
||||
// for has_errors() to be sure that compilation isn't
|
||||
// happening anyway. In that case, why inundate the user.
|
||||
if ty::type_needs_infer(self_ty) &&
|
||||
tcx.sess.has_errors()
|
||||
{
|
||||
debug!("skipping printout because self_ty={}",
|
||||
self_ty.repr(tcx));
|
||||
continue;
|
||||
}
|
||||
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
(*obligation).clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,17 @@
|
|||
* Trait Resolution. See doc.rs.
|
||||
*/
|
||||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::InferCtxt;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::nodemap::DefIdMap;
|
||||
|
||||
pub use self::fulfill::FulfillmentContext;
|
||||
pub use self::select::SelectionContext;
|
||||
pub use self::select::SelectionCache;
|
||||
pub use self::util::supertraits;
|
||||
pub use self::util::transitive_bounds;
|
||||
pub use self::util::Supertraits;
|
||||
|
@ -68,16 +69,22 @@ pub enum ObligationCauseCode {
|
|||
/// Obligation incurred due to an object cast.
|
||||
ObjectCastObligation(/* Object type */ ty::t),
|
||||
|
||||
/// To implement drop, type must be sendable.
|
||||
DropTrait,
|
||||
|
||||
/// Various cases where expressions must be sized/copy/etc:
|
||||
AssignmentLhsSized, // L = X implies that L is Sized
|
||||
StructInitializerSized, // S { ... } must be Sized
|
||||
VariableType(ast::NodeId), // Type of each variable must be Sized
|
||||
RepeatVec, // [T,..n] --> T must be Copy
|
||||
}
|
||||
|
||||
pub static DUMMY_CAUSE: ObligationCause =
|
||||
ObligationCause { span: DUMMY_SP,
|
||||
code: MiscObligation };
|
||||
// Captures of variable the given id by a closure (span is the
|
||||
// span of the closure)
|
||||
ClosureCapture(ast::NodeId, Span),
|
||||
|
||||
// Types of fields (other than the last) in a struct must be sized.
|
||||
FieldSized,
|
||||
}
|
||||
|
||||
pub type Obligations = subst::VecPerParamSpace<Obligation>;
|
||||
|
||||
|
@ -208,31 +215,11 @@ pub struct VtableParamData {
|
|||
pub bound: Rc<ty::TraitRef>,
|
||||
}
|
||||
|
||||
pub fn try_select_obligation(infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
|
||||
obligation: &Obligation)
|
||||
-> SelectionResult<Selection>
|
||||
{
|
||||
/*!
|
||||
* Attempts to select the impl/bound/etc for the obligation
|
||||
* given. Returns `None` if we are unable to resolve, either
|
||||
* because of ambiguity or due to insufficient inference. Note
|
||||
* that selection is a shallow process and hence the result may
|
||||
* contain nested obligations that must be resolved. The caller is
|
||||
* responsible for ensuring that those get resolved. (But see
|
||||
* `try_select_obligation_deep` below.)
|
||||
*/
|
||||
|
||||
let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures);
|
||||
selcx.select(obligation)
|
||||
}
|
||||
|
||||
pub fn evaluate_obligation(infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
obligation: &Obligation,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>)
|
||||
-> EvaluationResult
|
||||
pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
obligation: &Obligation,
|
||||
typer: &Typer<'tcx>)
|
||||
-> EvaluationResult
|
||||
{
|
||||
/*!
|
||||
* Attempts to resolve the obligation given. Returns `None` if
|
||||
|
@ -240,18 +227,17 @@ pub fn evaluate_obligation(infcx: &InferCtxt,
|
|||
* due to insufficient inference.
|
||||
*/
|
||||
|
||||
let selcx = select::SelectionContext::new(infcx, param_env,
|
||||
unboxed_closures);
|
||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
||||
selcx.evaluate_obligation(obligation)
|
||||
}
|
||||
|
||||
pub fn evaluate_impl(infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
|
||||
cause: ObligationCause,
|
||||
impl_def_id: ast::DefId,
|
||||
self_ty: ty::t)
|
||||
-> EvaluationResult
|
||||
pub fn evaluate_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
typer: &Typer<'tcx>,
|
||||
cause: ObligationCause,
|
||||
impl_def_id: ast::DefId,
|
||||
self_ty: ty::t)
|
||||
-> EvaluationResult
|
||||
{
|
||||
/*!
|
||||
* Tests whether the impl `impl_def_id` can be applied to the self
|
||||
|
@ -264,17 +250,17 @@ pub fn evaluate_impl(infcx: &InferCtxt,
|
|||
* (yes/no/unknown).
|
||||
*/
|
||||
|
||||
let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures);
|
||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
||||
selcx.evaluate_impl(impl_def_id, cause, self_ty)
|
||||
}
|
||||
|
||||
pub fn select_inherent_impl(infcx: &InferCtxt,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
unboxed_closures: &DefIdMap<ty::UnboxedClosure>,
|
||||
cause: ObligationCause,
|
||||
impl_def_id: ast::DefId,
|
||||
self_ty: ty::t)
|
||||
-> SelectionResult<VtableImplData<Obligation>>
|
||||
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment,
|
||||
typer: &Typer<'tcx>,
|
||||
cause: ObligationCause,
|
||||
impl_def_id: ast::DefId,
|
||||
self_ty: ty::t)
|
||||
-> SelectionResult<VtableImplData<Obligation>>
|
||||
{
|
||||
/*!
|
||||
* Matches the self type of the inherent impl `impl_def_id`
|
||||
|
@ -293,8 +279,7 @@ pub fn select_inherent_impl(infcx: &InferCtxt,
|
|||
// `try_resolve_obligation()`.
|
||||
assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none());
|
||||
|
||||
let selcx = select::SelectionContext::new(infcx, param_env,
|
||||
unboxed_closures);
|
||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
||||
selcx.select_inherent_impl(impl_def_id, cause, self_ty)
|
||||
}
|
||||
|
||||
|
@ -376,6 +361,10 @@ impl ObligationCause {
|
|||
pub fn misc(span: Span) -> ObligationCause {
|
||||
ObligationCause { span: span, code: MiscObligation }
|
||||
}
|
||||
|
||||
pub fn dummy() -> ObligationCause {
|
||||
ObligationCause { span: DUMMY_SP, code: MiscObligation }
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> Vtable<N> {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,7 @@ use middle::subst;
|
|||
use middle::subst::{ParamSpace, Subst, Substs, VecPerParamSpace};
|
||||
use middle::typeck::infer::InferCtxt;
|
||||
use middle::ty;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
|
@ -27,6 +28,7 @@ use super::{Obligation, ObligationCause, VtableImpl, VtableParam, VtableParamDat
|
|||
pub struct Supertraits<'cx, 'tcx:'cx> {
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
stack: Vec<SupertraitEntry>,
|
||||
visited: HashSet<Rc<ty::TraitRef>>,
|
||||
}
|
||||
|
||||
struct SupertraitEntry {
|
||||
|
@ -62,15 +64,34 @@ pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
|||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let bounds = Vec::from_fn(bounds.len(), |i| bounds[i].clone());
|
||||
|
||||
let visited: HashSet<Rc<ty::TraitRef>> =
|
||||
bounds.iter()
|
||||
.map(|b| (*b).clone())
|
||||
.collect();
|
||||
|
||||
let entry = SupertraitEntry { position: 0, supertraits: bounds };
|
||||
Supertraits { tcx: tcx, stack: vec![entry] }
|
||||
Supertraits { tcx: tcx, stack: vec![entry], visited: visited }
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Supertraits<'cx, 'tcx> {
|
||||
fn push(&mut self, trait_ref: &ty::TraitRef) {
|
||||
let bounds = ty::bounds_for_trait_ref(self.tcx, trait_ref);
|
||||
let entry = SupertraitEntry { position: 0,
|
||||
supertraits: bounds.trait_bounds };
|
||||
let ty::ParamBounds { builtin_bounds, mut trait_bounds, .. } =
|
||||
ty::bounds_for_trait_ref(self.tcx, trait_ref);
|
||||
for builtin_bound in builtin_bounds.iter() {
|
||||
let bound_trait_ref = trait_ref_for_builtin_bound(self.tcx,
|
||||
builtin_bound,
|
||||
trait_ref.self_ty());
|
||||
trait_bounds.push(bound_trait_ref);
|
||||
}
|
||||
|
||||
// Only keep those bounds that we haven't already seen. This
|
||||
// is necessary to prevent infinite recursion in some cases.
|
||||
// One common case is when people define `trait Sized { }`
|
||||
// rather than `trait Sized for Sized? { }`.
|
||||
trait_bounds.retain(|r| self.visited.insert((*r).clone()));
|
||||
|
||||
let entry = SupertraitEntry { position: 0, supertraits: trait_bounds };
|
||||
self.stack.push(entry);
|
||||
}
|
||||
|
||||
|
@ -211,6 +232,25 @@ fn push_obligations_for_param_bounds(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trait_ref_for_builtin_bound(
|
||||
tcx: &ty::ctxt,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
param_ty: ty::t)
|
||||
-> Rc<ty::TraitRef>
|
||||
{
|
||||
match tcx.lang_items.from_builtin_kind(builtin_bound) {
|
||||
Ok(def_id) => {
|
||||
Rc::new(ty::TraitRef {
|
||||
def_id: def_id,
|
||||
substs: Substs::empty().with_self_ty(param_ty)
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
tcx.sess.bug(e.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn obligation_for_builtin_bound(
|
||||
tcx: &ty::ctxt,
|
||||
cause: ObligationCause,
|
||||
|
@ -219,20 +259,11 @@ pub fn obligation_for_builtin_bound(
|
|||
param_ty: ty::t)
|
||||
-> Obligation
|
||||
{
|
||||
match tcx.lang_items.from_builtin_kind(builtin_bound) {
|
||||
Ok(def_id) => {
|
||||
Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: Rc::new(ty::TraitRef {
|
||||
def_id: def_id,
|
||||
substs: Substs::empty().with_self_ty(param_ty),
|
||||
}),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tcx.sess.span_bug(cause.span, e.as_slice());
|
||||
}
|
||||
let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty);
|
||||
Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: trait_ref
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ use middle::trans::type_of;
|
|||
use middle::traits;
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::typeck;
|
||||
use middle::typeck::infer;
|
||||
use util::ppaux::Repr;
|
||||
|
@ -791,12 +792,10 @@ pub fn fulfill_obligation(ccx: &CrateContext,
|
|||
// Parameter environment is used to give details about type parameters,
|
||||
// but since we are in trans, everything is fully monomorphized.
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let unboxed_closures = tcx.unboxed_closures.borrow();
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
let selcx = traits::SelectionContext::new(&infcx, ¶m_env,
|
||||
&*unboxed_closures);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let obligation = traits::Obligation::misc(span, trait_ref.clone());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(selection)) => selection,
|
||||
|
@ -825,7 +824,7 @@ pub fn fulfill_obligation(ccx: &CrateContext,
|
|||
let vtable = selection.map_move_nested(|obligation| {
|
||||
fulfill_cx.register_obligation(tcx, obligation);
|
||||
});
|
||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, &*unboxed_closures) {
|
||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
tcx.sess.span_bug(
|
||||
|
@ -841,7 +840,7 @@ pub fn fulfill_obligation(ccx: &CrateContext,
|
|||
// sort of overkill because we do not expect there to be any
|
||||
// unbound type variables, hence no skolemized types should ever
|
||||
// be inserted.
|
||||
let vtable = infer::skolemize(&infcx, vtable);
|
||||
let vtable = vtable.fold_with(&mut infcx.skolemizer());
|
||||
|
||||
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
||||
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
||||
|
|
|
@ -561,6 +561,9 @@ pub fn get_vtable(bcx: Block,
|
|||
DUMMY_SP,
|
||||
trait_ref.clone());
|
||||
match vtable {
|
||||
traits::VtableBuiltin => {
|
||||
Vec::new().into_iter()
|
||||
}
|
||||
traits::VtableImpl(
|
||||
traits::VtableImplData {
|
||||
impl_def_id: id,
|
||||
|
@ -634,7 +637,6 @@ pub fn get_vtable(bcx: Block,
|
|||
|
||||
(vec!(llfn)).into_iter()
|
||||
}
|
||||
traits::VtableBuiltin |
|
||||
traits::VtableParam(..) => {
|
||||
bcx.sess().bug(
|
||||
format!("resolved vtable for {} to bad vtable {} in trans",
|
||||
|
|
|
@ -579,6 +579,10 @@ pub struct ctxt<'tcx> {
|
|||
/// Maps def IDs of traits to information about their associated types.
|
||||
pub trait_associated_types:
|
||||
RefCell<DefIdMap<Rc<Vec<AssociatedTypeInfo>>>>,
|
||||
|
||||
/// Caches the results of trait selection. This cache is used
|
||||
/// for things that do not have to do with the parameters in scope.
|
||||
pub selection_cache: traits::SelectionCache,
|
||||
}
|
||||
|
||||
pub enum tbox_flag {
|
||||
|
@ -1281,6 +1285,10 @@ pub struct ParameterEnvironment {
|
|||
/// Note: This effectively *duplicates* the `bounds` array for
|
||||
/// now.
|
||||
pub caller_obligations: VecPerParamSpace<traits::Obligation>,
|
||||
|
||||
/// Caches the results of trait selection. This cache is used
|
||||
/// for things that have to do with the parameters in scope.
|
||||
pub selection_cache: traits::SelectionCache,
|
||||
}
|
||||
|
||||
impl ParameterEnvironment {
|
||||
|
@ -1524,7 +1532,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||
capture_modes: capture_modes,
|
||||
associated_types: RefCell::new(DefIdMap::new()),
|
||||
trait_associated_types: RefCell::new(DefIdMap::new()),
|
||||
}
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Type constructors
|
||||
|
@ -2235,35 +2244,25 @@ def_type_content_sets!(
|
|||
OwnsAll = 0b0000_0000__1111_1111__0000,
|
||||
|
||||
// Things that are reachable by the value in any way (fourth nibble):
|
||||
ReachesNonsendAnnot = 0b0000_0001__0000_0000__0000,
|
||||
ReachesBorrowed = 0b0000_0010__0000_0000__0000,
|
||||
// ReachesManaged /* see [1] below */ = 0b0000_0100__0000_0000__0000,
|
||||
ReachesMutable = 0b0000_1000__0000_0000__0000,
|
||||
ReachesNoSync = 0b0001_0000__0000_0000__0000,
|
||||
ReachesFfiUnsafe = 0b0010_0000__0000_0000__0000,
|
||||
ReachesAll = 0b0011_1111__0000_0000__0000,
|
||||
|
||||
// Things that cause values to *move* rather than *copy*
|
||||
// Things that cause values to *move* rather than *copy*. This
|
||||
// is almost the same as the `Copy` trait, but for managed
|
||||
// data -- atm, we consider managed data to copy, not move,
|
||||
// but it does not impl Copy as a pure memcpy is not good
|
||||
// enough. Yuck.
|
||||
Moves = 0b0000_0000__0000_1011__0000,
|
||||
|
||||
// Things that mean drop glue is necessary
|
||||
NeedsDrop = 0b0000_0000__0000_0111__0000,
|
||||
|
||||
// Things that prevent values from being sent
|
||||
//
|
||||
// Note: For checking whether something is sendable, it'd
|
||||
// be sufficient to have ReachesManaged. However, we include
|
||||
// both ReachesManaged and OwnsManaged so that when
|
||||
// a parameter has a bound T:Send, we are able to deduce
|
||||
// that it neither reaches nor owns a managed pointer.
|
||||
Nonsendable = 0b0000_0111__0000_0100__0000,
|
||||
|
||||
// Things that prevent values from being considered sized
|
||||
Nonsized = 0b0000_0000__0000_0000__0001,
|
||||
|
||||
// Things that prevent values from being sync
|
||||
Nonsync = 0b0001_0000__0000_0000__0000,
|
||||
|
||||
// Things that make values considered not POD (would be same
|
||||
// as `Moves`, but for the fact that managed data `@` is
|
||||
// not considered POD)
|
||||
|
@ -2282,15 +2281,6 @@ def_type_content_sets!(
|
|||
)
|
||||
|
||||
impl TypeContents {
|
||||
pub fn meets_builtin_bound(&self, cx: &ctxt, bb: BuiltinBound) -> bool {
|
||||
match bb {
|
||||
BoundSend => self.is_sendable(cx),
|
||||
BoundSized => self.is_sized(cx),
|
||||
BoundCopy => self.is_copy(cx),
|
||||
BoundSync => self.is_sync(cx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn when(&self, cond: bool) -> TypeContents {
|
||||
if cond {*self} else {TC::None}
|
||||
}
|
||||
|
@ -2299,14 +2289,6 @@ impl TypeContents {
|
|||
(self.bits & tc.bits) != 0
|
||||
}
|
||||
|
||||
pub fn is_sendable(&self, _: &ctxt) -> bool {
|
||||
!self.intersects(TC::Nonsendable)
|
||||
}
|
||||
|
||||
pub fn is_sync(&self, _: &ctxt) -> bool {
|
||||
!self.intersects(TC::Nonsync)
|
||||
}
|
||||
|
||||
pub fn owns_managed(&self) -> bool {
|
||||
self.intersects(TC::OwnsManaged)
|
||||
}
|
||||
|
@ -2319,10 +2301,6 @@ impl TypeContents {
|
|||
!self.intersects(TC::Nonsized)
|
||||
}
|
||||
|
||||
pub fn is_copy(&self, _: &ctxt) -> bool {
|
||||
!self.intersects(TC::Noncopy)
|
||||
}
|
||||
|
||||
pub fn interior_unsafe(&self) -> bool {
|
||||
self.intersects(TC::InteriorUnsafe)
|
||||
}
|
||||
|
@ -2407,10 +2385,6 @@ impl fmt::Show for TypeContents {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn type_is_sendable(cx: &ctxt, t: ty::t) -> bool {
|
||||
type_contents(cx, t).is_sendable(cx)
|
||||
}
|
||||
|
||||
pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool {
|
||||
type_contents(cx, t).interior_unsafe()
|
||||
}
|
||||
|
@ -2652,19 +2626,14 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
|||
fn apply_lang_items(cx: &ctxt,
|
||||
did: ast::DefId,
|
||||
tc: TypeContents)
|
||||
-> TypeContents {
|
||||
if Some(did) == cx.lang_items.no_send_bound() {
|
||||
tc | TC::ReachesNonsendAnnot
|
||||
} else if Some(did) == cx.lang_items.managed_bound() {
|
||||
-> TypeContents
|
||||
{
|
||||
if Some(did) == cx.lang_items.managed_bound() {
|
||||
tc | TC::Managed
|
||||
} else if Some(did) == cx.lang_items.no_copy_bound() {
|
||||
tc | TC::OwnsAffine
|
||||
} else if Some(did) == cx.lang_items.no_sync_bound() {
|
||||
tc | TC::ReachesNoSync
|
||||
} else if Some(did) == cx.lang_items.unsafe_type() {
|
||||
// FIXME(#13231): This shouldn't be needed after
|
||||
// opt-in built-in bounds are implemented.
|
||||
(tc | TC::InteriorUnsafe) - TC::Nonsync
|
||||
tc | TC::InteriorUnsafe
|
||||
} else {
|
||||
tc
|
||||
}
|
||||
|
@ -2724,10 +2693,9 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
|||
let mut tc = TC::All;
|
||||
each_inherited_builtin_bound(cx, bounds, traits, |bound| {
|
||||
tc = tc - match bound {
|
||||
BoundSend => TC::Nonsendable,
|
||||
BoundSync | BoundSend => TC::None,
|
||||
BoundSized => TC::Nonsized,
|
||||
BoundCopy => TC::Noncopy,
|
||||
BoundSync => TC::Nonsync,
|
||||
};
|
||||
});
|
||||
return tc;
|
||||
|
@ -5324,7 +5292,8 @@ pub fn empty_parameter_environment() -> ParameterEnvironment {
|
|||
ty::ParameterEnvironment { free_substs: Substs::empty(),
|
||||
bounds: VecPerParamSpace::empty(),
|
||||
caller_obligations: VecPerParamSpace::empty(),
|
||||
implicit_region_bound: ty::ReEmpty }
|
||||
implicit_region_bound: ty::ReEmpty,
|
||||
selection_cache: traits::SelectionCache::new(), }
|
||||
}
|
||||
|
||||
pub fn construct_parameter_environment(
|
||||
|
@ -5396,6 +5365,7 @@ pub fn construct_parameter_environment(
|
|||
bounds: bounds,
|
||||
implicit_region_bound: ty::ReScope(free_id),
|
||||
caller_obligations: obligations,
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
};
|
||||
|
||||
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
|
||||
|
|
|
@ -298,30 +298,29 @@ impl<'a, 'tcx> mem_categorization::Typer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
self.ccx.tcx
|
||||
}
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<ty::t> {
|
||||
self.ccx.tcx.node_ty(id)
|
||||
Ok(self.node_ty(id))
|
||||
}
|
||||
fn node_method_ty(&self, method_call: typeck::MethodCall)
|
||||
-> Option<ty::t> {
|
||||
self.ccx.tcx.node_method_ty(method_call)
|
||||
self.inh.method_map.borrow().find(&method_call).map(|m| m.ty)
|
||||
}
|
||||
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
|
||||
self.ccx.tcx.adjustments()
|
||||
&self.inh.adjustments
|
||||
}
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.ccx.tcx.is_method_call(id)
|
||||
self.inh.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
|
||||
}
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId> {
|
||||
self.ccx.tcx.temporary_scope(rvalue_id)
|
||||
self.tcx().temporary_scope(rvalue_id)
|
||||
}
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||
self.ccx.tcx.upvar_borrow(upvar_id)
|
||||
self.inh.upvar_borrow_map.borrow().get_copy(&upvar_id)
|
||||
}
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause {
|
||||
self.ccx.tcx.capture_mode(closure_expr_id)
|
||||
}
|
||||
fn unboxed_closures<'a>(&'a self)
|
||||
-> &'a RefCell<DefIdMap<ty::UnboxedClosure>> {
|
||||
fn unboxed_closures<'a>(&'a self) -> &'a RefCell<DefIdMap<ty::UnboxedClosure>> {
|
||||
&self.inh.unboxed_closures
|
||||
}
|
||||
}
|
||||
|
@ -369,12 +368,7 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
|
|||
-> Inherited<'a, 'tcx> {
|
||||
// It's kind of a kludge to manufacture a fake function context
|
||||
// and statement context, but we might as well do write the code only once
|
||||
let param_env = ty::ParameterEnvironment {
|
||||
free_substs: subst::Substs::empty(),
|
||||
bounds: subst::VecPerParamSpace::empty(),
|
||||
implicit_region_bound: ty::ReStatic,
|
||||
caller_obligations: subst::VecPerParamSpace::empty(),
|
||||
};
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
Inherited::new(ccx.tcx, param_env)
|
||||
}
|
||||
|
||||
|
@ -387,17 +381,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct CheckItemSizedTypesVisitor<'a, 'tcx: 'a> {
|
||||
ccx: &'a CrateCtxt<'a, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemSizedTypesVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &ast::Item) {
|
||||
check_item_sized(self.ccx, i);
|
||||
visit::walk_item(self, i);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_item_types(ccx: &CrateCtxt) {
|
||||
let krate = ccx.tcx.map.krate();
|
||||
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
|
||||
|
@ -411,9 +394,6 @@ pub fn check_item_types(ccx: &CrateCtxt) {
|
|||
visit::walk_crate(&mut visit, krate);
|
||||
|
||||
ccx.tcx.sess.abort_if_errors();
|
||||
|
||||
let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
|
||||
visit::walk_crate(&mut visit, krate);
|
||||
}
|
||||
|
||||
fn check_bare_fn(ccx: &CrateCtxt,
|
||||
|
@ -435,7 +415,6 @@ fn check_bare_fn(ccx: &CrateCtxt,
|
|||
vtable2::select_all_fcx_obligations_or_error(&fcx);
|
||||
regionck::regionck_fn(&fcx, id, body);
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
vtable2::check_builtin_bound_obligations(&fcx); // must happen after writeback
|
||||
}
|
||||
_ => ccx.tcx.sess.impossible_case(body.span,
|
||||
"check_bare_fn: function type expected")
|
||||
|
@ -677,33 +656,6 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
fn check_fields_sized(tcx: &ty::ctxt,
|
||||
struct_def: &ast::StructDef) {
|
||||
let len = struct_def.fields.len();
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
for f in struct_def.fields.slice_to(len - 1).iter() {
|
||||
let t = ty::node_id_to_type(tcx, f.node.id);
|
||||
if !ty::type_is_sized(tcx, t) {
|
||||
match f.node.kind {
|
||||
ast::NamedField(ident, _) => {
|
||||
span_err!(tcx.sess, f.span, E0042,
|
||||
"type `{}` is dynamically sized. \
|
||||
dynamically sized types may only \
|
||||
appear as the type of the final \
|
||||
field in a struct",
|
||||
token::get_ident(ident));
|
||||
}
|
||||
ast::UnnamedField(_) => {
|
||||
span_err!(tcx.sess, f.span, E0043,
|
||||
"dynamically sized type in field");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
|
@ -718,24 +670,6 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
debug!("check_item(it.id={}, it.ident={})",
|
||||
it.id,
|
||||
ty::item_path_str(ccx.tcx, local_def(it.id)));
|
||||
let _indenter = indenter();
|
||||
|
||||
match it.node {
|
||||
ast::ItemEnum(ref enum_definition, _) => {
|
||||
check_enum_variants_sized(ccx,
|
||||
enum_definition.variants.as_slice());
|
||||
}
|
||||
ast::ItemStruct(..) => {
|
||||
check_fields_sized(ccx.tcx, &*ccx.tcx.map.expect_struct(it.id));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
debug!("check_item(it.id={}, it.ident={})",
|
||||
it.id,
|
||||
|
@ -4866,7 +4800,6 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
|
|||
vtable2::select_all_fcx_obligations_or_error(fcx);
|
||||
regionck::regionck_expr(fcx, e);
|
||||
writeback::resolve_type_vars_in_expr(fcx, e);
|
||||
vtable2::check_builtin_bound_obligations(fcx);
|
||||
}
|
||||
|
||||
/// Checks whether a type can be represented in memory. In particular, it
|
||||
|
@ -4954,39 +4887,6 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn check_enum_variants_sized(ccx: &CrateCtxt,
|
||||
vs: &[P<ast::Variant>]) {
|
||||
for v in vs.iter() {
|
||||
match v.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.len() > 0 => {
|
||||
let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
|
||||
let arg_tys: Vec<ty::t> = ty::ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
|
||||
let len = arg_tys.len();
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
for (i, t) in arg_tys.slice_to(len - 1).iter().enumerate() {
|
||||
// Allow the last field in an enum to be unsized.
|
||||
// We want to do this so that we can support smart pointers.
|
||||
// A struct value with an unsized final field is itself
|
||||
// unsized and we must track this in the type system.
|
||||
if !ty::type_is_sized(ccx.tcx, *t) {
|
||||
span_err!(ccx.tcx.sess, args.get(i).ty.span, E0078,
|
||||
"type `{}` is dynamically sized. dynamically sized types may only \
|
||||
appear as the final type in a variant",
|
||||
ppaux::ty_to_string(ccx.tcx, *t));
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
check_fields_sized(ccx.tcx, &**struct_def)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_enum_variants(ccx: &CrateCtxt,
|
||||
sp: Span,
|
||||
vs: &[P<ast::Variant>],
|
||||
|
|
|
@ -120,11 +120,13 @@ and report an error, and it just seems like more mess in the end.)
|
|||
|
||||
use middle::def;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::traits;
|
||||
use middle::ty::{ReScope};
|
||||
use middle::ty;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::FnCtxt;
|
||||
use middle::typeck::check::regionmanip;
|
||||
use middle::typeck::check::vtable2;
|
||||
use middle::typeck::infer::resolve_and_force_all_but_regions;
|
||||
use middle::typeck::infer::resolve_type;
|
||||
use middle::typeck::infer;
|
||||
|
@ -165,6 +167,11 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
|
|||
// regionck assumes typeck succeeded
|
||||
rcx.visit_fn_body(id, blk);
|
||||
}
|
||||
|
||||
// Region checking a fn can introduce new trait obligations,
|
||||
// particularly around closure bounds.
|
||||
vtable2::select_all_fcx_obligations_or_error(fcx);
|
||||
|
||||
fcx.infcx().resolve_regions_and_report_errors();
|
||||
}
|
||||
|
||||
|
@ -848,16 +855,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
}
|
||||
});
|
||||
}
|
||||
ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
|
||||
bounds: ref bounds,
|
||||
..}) => {
|
||||
// For proc, ensure that the *types* of the variables
|
||||
// outlive region bound, since they are captured by value.
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx, bounds.region_bound, expr, freevars);
|
||||
});
|
||||
}
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
// No free variables means that there is no environment and
|
||||
|
@ -868,8 +865,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
// NDM -- this seems wrong, discuss with pcwalton, should
|
||||
// be straightforward enough.
|
||||
if !freevars.is_empty() {
|
||||
let bounds = ty::region_existential_bound(region);
|
||||
ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx, region, expr, freevars);
|
||||
rcx, bounds, expr, freevars);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -881,20 +879,26 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
rcx.set_repeating_scope(repeating_scope);
|
||||
|
||||
match ty::get(function_type).sty {
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(..),
|
||||
..
|
||||
}) => {
|
||||
ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. }) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
propagate_upupvar_borrow_kind(rcx, expr, freevars);
|
||||
})
|
||||
}
|
||||
_ => ()
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match ty::get(function_type).sty {
|
||||
ty::ty_closure(box ty::ClosureTy {bounds, ..}) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
fn ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx: &mut Rcx,
|
||||
region_bound: ty::Region,
|
||||
bounds: ty::ExistentialBounds,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar])
|
||||
{
|
||||
|
@ -908,7 +912,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
let tcx = rcx.fcx.ccx.tcx;
|
||||
|
||||
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
|
||||
region_bound.repr(tcx), expr.repr(tcx));
|
||||
bounds.region_bound.repr(tcx), expr.repr(tcx));
|
||||
|
||||
for freevar in freevars.iter() {
|
||||
let var_node_id = {
|
||||
|
@ -917,11 +921,35 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
def_id.node
|
||||
};
|
||||
|
||||
let var_ty = rcx.resolve_node_type(var_node_id);
|
||||
// Compute the type of the field in the environment that
|
||||
// represents `var_node_id`. For a by-value closure, this
|
||||
// will be the same as the type of the variable. For a
|
||||
// by-reference closure, this will be `&T` where `T` is
|
||||
// the type of the variable.
|
||||
let raw_var_ty = rcx.resolve_node_type(var_node_id);
|
||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||
closure_expr_id: expr.id };
|
||||
let var_ty = match rcx.fcx.inh.upvar_borrow_map.borrow().find(&upvar_id) {
|
||||
Some(upvar_borrow) => {
|
||||
ty::mk_rptr(rcx.tcx(),
|
||||
upvar_borrow.region,
|
||||
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
||||
ty: raw_var_ty })
|
||||
}
|
||||
None => raw_var_ty
|
||||
};
|
||||
|
||||
// Check that the type meets the criteria of the existential bounds:
|
||||
for builtin_bound in bounds.builtin_bounds.iter() {
|
||||
let code = traits::ClosureCapture(var_node_id, expr.span);
|
||||
let cause = traits::ObligationCause::new(freevar.span, code);
|
||||
let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause,
|
||||
var_ty, builtin_bound);
|
||||
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(), obligation);
|
||||
}
|
||||
type_must_outlive(
|
||||
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
|
||||
var_ty, region_bound);
|
||||
var_ty, bounds.region_bound);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,32 +186,15 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
|||
debug!("select_all_fcx_obligations_or_error");
|
||||
|
||||
let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
|
||||
let r =
|
||||
fulfillment_cx.select_all_or_error(
|
||||
fcx.infcx(),
|
||||
&fcx.inh.param_env,
|
||||
&*fcx.inh.unboxed_closures.borrow());
|
||||
let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
|
||||
&fcx.inh.param_env,
|
||||
fcx);
|
||||
match r {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx, &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_bound_obligations(fcx: &FnCtxt) {
|
||||
/*!
|
||||
* Hacky second pass to check builtin-bounds obligations *after*
|
||||
* writeback occurs.
|
||||
*/
|
||||
|
||||
match
|
||||
fcx.inh.fulfillment_cx.borrow()
|
||||
.check_builtin_bound_obligations(fcx.infcx())
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx, &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation)
|
||||
-> (ty::TraitRef, ty::t)
|
||||
{
|
||||
|
@ -244,7 +227,8 @@ pub fn report_fulfillment_error(fcx: &FnCtxt,
|
|||
|
||||
pub fn report_selection_error(fcx: &FnCtxt,
|
||||
obligation: &Obligation,
|
||||
error: &SelectionError) {
|
||||
error: &SelectionError)
|
||||
{
|
||||
match *error {
|
||||
Unimplemented => {
|
||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||
|
@ -309,15 +293,31 @@ pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
|
|||
obligation.repr(fcx.tcx()));
|
||||
if ty::type_is_error(self_ty) {
|
||||
} else if ty::type_needs_infer(self_ty) {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"unable to infer enough type information to \
|
||||
locate the impl of the trait `{}` for \
|
||||
the type `{}`; type annotations required",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
self_ty.user_string(fcx.tcx())).as_slice());
|
||||
note_obligation_cause(fcx, obligation);
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
// a bunch of uninteresting errors saying something like "<generic
|
||||
// #0> doesn't implement Sized". It may even be true that we
|
||||
// could just skip over all checks where the self-ty is an
|
||||
// inference variable, but I was afraid that there might be an
|
||||
// inference variable created, registered as an obligation, and
|
||||
// then never forced by writeback, and hence by skipping here we'd
|
||||
// be ignoring the fact that we don't KNOW the type works
|
||||
// out. Though even that would probably be harmless, given that
|
||||
// we're only talking about builtin traits, which are known to be
|
||||
// inhabited. But in any case I just threw in this check for
|
||||
// has_errors() to be sure that compilation isn't happening
|
||||
// anyway. In that case, why inundate the user.
|
||||
if !fcx.tcx().sess.has_errors() {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"unable to infer enough type information to \
|
||||
locate the impl of the trait `{}` for \
|
||||
the type `{}`; type annotations required",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
self_ty.user_string(fcx.tcx())).as_slice());
|
||||
note_obligation_cause(fcx, obligation);
|
||||
}
|
||||
} else if fcx.tcx().sess.err_count() == 0 {
|
||||
// Ambiguity. Coherence should have reported an error.
|
||||
fcx.tcx().sess.span_bug(
|
||||
|
@ -337,9 +337,7 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
|
|||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_where_possible(fcx.infcx(),
|
||||
&fcx.inh.param_env,
|
||||
&*fcx.inh.unboxed_closures.borrow())
|
||||
.select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx, &errors); }
|
||||
|
@ -392,5 +390,26 @@ fn note_obligation_cause(fcx: &FnCtxt,
|
|||
obligation.cause.span,
|
||||
"structs must have a statically known size to be initialized");
|
||||
}
|
||||
traits::DropTrait => {
|
||||
span_note!(tcx.sess, obligation.cause.span,
|
||||
"cannot implement a destructor on a \
|
||||
structure or enumeration that does not satisfy Send");
|
||||
span_note!(tcx.sess, obligation.cause.span,
|
||||
"use \"#[unsafe_destructor]\" on the implementation \
|
||||
to force the compiler to allow this");
|
||||
}
|
||||
traits::ClosureCapture(var_id, closure_span) => {
|
||||
let name = ty::local_var_name_str(tcx, var_id);
|
||||
span_note!(tcx.sess, closure_span,
|
||||
"the closure that captures `{}` requires that all captured variables \"
|
||||
implement the trait `{}`",
|
||||
name,
|
||||
trait_name);
|
||||
}
|
||||
traits::FieldSized => {
|
||||
span_note!(tcx.sess, obligation.cause.span,
|
||||
"only the last field of a struct or enum variant \
|
||||
may have a dynamically sized type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst};
|
||||
use middle::traits;
|
||||
use middle::ty;
|
||||
|
@ -21,6 +22,7 @@ use util::ppaux::Repr;
|
|||
use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util::{local_def};
|
||||
use syntax::attr;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
|
@ -57,7 +59,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
item.id,
|
||||
ty::item_path_str(ccx.tcx, local_def(item.id)));
|
||||
|
||||
let ccx = self.ccx;
|
||||
match item.node {
|
||||
ast::ItemImpl(..) => {
|
||||
self.check_impl(item);
|
||||
|
@ -68,26 +69,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
ast::ItemStatic(..) => {
|
||||
self.check_item_type(item);
|
||||
}
|
||||
ast::ItemStruct(..) => {
|
||||
ast::ItemStruct(ref struct_def, _) => {
|
||||
self.check_type_defn(item, |fcx| {
|
||||
ty::struct_fields(ccx.tcx, local_def(item.id),
|
||||
&fcx.inh.param_env.free_substs)
|
||||
.iter()
|
||||
.map(|f| f.mt.ty)
|
||||
.collect()
|
||||
vec![struct_variant(fcx, &**struct_def)]
|
||||
});
|
||||
}
|
||||
ast::ItemEnum(..) => {
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
self.check_type_defn(item, |fcx| {
|
||||
ty::substd_enum_variants(ccx.tcx, local_def(item.id),
|
||||
&fcx.inh.param_env.free_substs)
|
||||
.iter()
|
||||
.flat_map(|variant| {
|
||||
variant.args
|
||||
.iter()
|
||||
.map(|&arg_ty| arg_ty)
|
||||
})
|
||||
.collect()
|
||||
enum_variants(fcx, enum_def)
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
|
@ -110,12 +99,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
f(self, &fcx);
|
||||
vtable2::select_all_fcx_obligations_or_error(&fcx);
|
||||
regionck::regionck_item(&fcx, item);
|
||||
vtable2::check_builtin_bound_obligations(&fcx);
|
||||
}
|
||||
|
||||
fn check_type_defn(&mut self,
|
||||
item: &ast::Item,
|
||||
lookup_fields: |&FnCtxt| -> Vec<ty::t>)
|
||||
lookup_fields: |&FnCtxt| -> Vec<AdtVariant>)
|
||||
{
|
||||
/*!
|
||||
* In a type definition, we check that to ensure that the types of the fields are
|
||||
|
@ -123,14 +111,31 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
*/
|
||||
|
||||
self.with_fcx(self.ccx, item, |this, fcx| {
|
||||
let field_tys = lookup_fields(fcx);
|
||||
let variants = lookup_fields(fcx);
|
||||
let mut bounds_checker = BoundsChecker::new(fcx, item.span,
|
||||
item.id, Some(&mut this.cache));
|
||||
for &ty in field_tys.iter() {
|
||||
// Regions are checked below.
|
||||
bounds_checker.check_traits_in_ty(ty);
|
||||
for variant in variants.iter() {
|
||||
for field in variant.fields.iter() {
|
||||
// Regions are checked below.
|
||||
bounds_checker.check_traits_in_ty(field.ty);
|
||||
}
|
||||
|
||||
// For DST, all intermediate types must be sized.
|
||||
if variant.fields.len() > 0 {
|
||||
for field in variant.fields.init().iter() {
|
||||
let cause = traits::ObligationCause::new(field.span, traits::FieldSized);
|
||||
fcx.register_obligation(
|
||||
traits::obligation_for_builtin_bound(fcx.tcx(),
|
||||
cause,
|
||||
field.ty,
|
||||
ty::BoundSized));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_tys: Vec<ty::t> =
|
||||
variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect();
|
||||
|
||||
regionck::regionck_ensure_component_tys_wf(
|
||||
fcx, item.span, field_tys.as_slice());
|
||||
});
|
||||
|
@ -166,6 +171,22 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
};
|
||||
let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
|
||||
// There are special rules that apply to drop.
|
||||
if
|
||||
fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) &&
|
||||
!attr::contains_name(item.attrs.as_slice(), "unsafe_destructor")
|
||||
{
|
||||
match ty::get(self_ty).sty {
|
||||
ty::ty_struct(def_id, _) |
|
||||
ty::ty_enum(def_id, _) => {
|
||||
check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id);
|
||||
}
|
||||
_ => {
|
||||
// Coherence already reports an error in this case.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are stricter on the trait-ref in an impl than the
|
||||
// self-type. In particular, we enforce region
|
||||
// relationships. The reason for this is that (at least
|
||||
|
@ -363,3 +384,87 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
t // we're not folding to produce a new type, so just return `t` here
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ADT
|
||||
|
||||
struct AdtVariant {
|
||||
fields: Vec<AdtField>,
|
||||
}
|
||||
|
||||
struct AdtField {
|
||||
ty: ty::t,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn struct_variant(fcx: &FnCtxt, struct_def: &ast::StructDef) -> AdtVariant {
|
||||
let fields =
|
||||
struct_def.fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
|
||||
let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
AdtField { ty: field_ty, span: field.span }
|
||||
})
|
||||
.collect();
|
||||
AdtVariant { fields: fields }
|
||||
}
|
||||
|
||||
fn enum_variants(fcx: &FnCtxt, enum_def: &ast::EnumDef) -> Vec<AdtVariant> {
|
||||
enum_def.variants.iter()
|
||||
.map(|variant| {
|
||||
match variant.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.len() > 0 => {
|
||||
let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
|
||||
let arg_tys = ty::ty_fn_args(ctor_ty);
|
||||
AdtVariant {
|
||||
fields: args.iter().enumerate().map(|(index, arg)| {
|
||||
let arg_ty = arg_tys[index];
|
||||
let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
AdtField {
|
||||
ty: arg_ty,
|
||||
span: arg.ty.span
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
ast::TupleVariantKind(_) => {
|
||||
AdtVariant {
|
||||
fields: Vec::new()
|
||||
}
|
||||
}
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
struct_variant(fcx, &**struct_def)
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Special drop trait checking
|
||||
|
||||
fn check_struct_safe_for_destructor(fcx: &FnCtxt,
|
||||
span: Span,
|
||||
self_ty: ty::t,
|
||||
struct_did: ast::DefId) {
|
||||
let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did);
|
||||
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
|
||||
&& !struct_tpt.generics.has_region_params(subst::TypeSpace)
|
||||
{
|
||||
let cause = traits::ObligationCause::new(span, traits::DropTrait);
|
||||
fcx.register_obligation(
|
||||
traits::obligation_for_builtin_bound(
|
||||
fcx.tcx(),
|
||||
cause,
|
||||
self_ty,
|
||||
ty::BoundSend));
|
||||
} else {
|
||||
span_err!(fcx.tcx().sess, span, E0141,
|
||||
"cannot implement a destructor on a structure \
|
||||
with type parameters");
|
||||
span_note!(fcx.tcx().sess, span,
|
||||
"use \"#[unsafe_destructor]\" on the implementation \
|
||||
to force the compiler to allow this");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1560,7 +1560,7 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
|
|||
"...so that it can be closed over into an object");
|
||||
}
|
||||
infer::RelateProcBound(span, var_node_id, _ty) => {
|
||||
self.tcx.sess.span_err(
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!(
|
||||
"...so that the variable `{}` can be captured \
|
||||
|
|
|
@ -13,20 +13,20 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub use middle::ty::IntVarValue;
|
||||
pub use middle::typeck::infer::resolve::resolve_and_force_all_but_regions;
|
||||
pub use middle::typeck::infer::resolve::{force_all, not_regions};
|
||||
pub use middle::typeck::infer::resolve::{force_ivar};
|
||||
pub use middle::typeck::infer::resolve::{force_tvar, force_rvar};
|
||||
pub use middle::typeck::infer::resolve::{resolve_ivar, resolve_all};
|
||||
pub use middle::typeck::infer::resolve::{resolve_nested_tvar};
|
||||
pub use middle::typeck::infer::resolve::{resolve_rvar};
|
||||
pub use self::resolve::resolve_and_force_all_but_regions;
|
||||
pub use self::resolve::{force_all, not_regions};
|
||||
pub use self::resolve::{force_ivar};
|
||||
pub use self::resolve::{force_tvar, force_rvar};
|
||||
pub use self::resolve::{resolve_ivar, resolve_all};
|
||||
pub use self::resolve::{resolve_nested_tvar};
|
||||
pub use self::resolve::{resolve_rvar};
|
||||
pub use self::skolemize::TypeSkolemizer;
|
||||
|
||||
use middle::subst;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
|
||||
use middle::ty;
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
||||
use middle::typeck::infer::coercion::Coerce;
|
||||
|
@ -382,13 +382,6 @@ pub fn verify_param_bound(cx: &InferCtxt,
|
|||
cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
|
||||
}
|
||||
|
||||
pub fn skolemize<T:TypeFoldable+Repr>(cx: &InferCtxt, a: T) -> T {
|
||||
let mut skol = skolemize::TypeSkolemizer::new(cx);
|
||||
let b = a.fold_with(&mut skol);
|
||||
debug!("skol(a={}) -> {}", a.repr(cx.tcx), b.repr(cx.tcx));
|
||||
b
|
||||
}
|
||||
|
||||
pub fn mk_eqty(cx: &InferCtxt,
|
||||
a_is_expected: bool,
|
||||
origin: TypeOrigin,
|
||||
|
@ -513,6 +506,10 @@ pub struct CombinedSnapshot {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub fn skolemizer<'a>(&'a self) -> TypeSkolemizer<'a, 'tcx> {
|
||||
skolemize::TypeSkolemizer::new(self)
|
||||
}
|
||||
|
||||
pub fn combine_fields<'a>(&'a self, a_is_expected: bool, trace: TypeTrace)
|
||||
-> CombineFields<'a, 'tcx> {
|
||||
CombineFields {infcx: self,
|
||||
|
|
|
@ -119,9 +119,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
|
|||
self.probe_unifiable(v)
|
||||
}
|
||||
|
||||
ty::ty_infer(ty::SkolemizedTy(_)) |
|
||||
ty::ty_infer(ty::SkolemizedIntTy(_)) => {
|
||||
self.tcx().sess.bug("Cannot skolemize a skolemized type");
|
||||
ty::ty_infer(ty::SkolemizedTy(c)) |
|
||||
ty::ty_infer(ty::SkolemizedIntTy(c)) => {
|
||||
if c >= self.skolemization_count {
|
||||
self.tcx().sess.bug(
|
||||
format!("Encountered a skolemized type with id {} \
|
||||
but our counter is only at {}",
|
||||
c,
|
||||
self.skolemization_count).as_slice());
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
ty::ty_open(..) => {
|
||||
|
|
|
@ -12,8 +12,9 @@ fn bar(blk: ||:'static) {
|
|||
}
|
||||
|
||||
fn foo(x: &()) {
|
||||
bar(|| {
|
||||
let _ = x; //~ ERROR captured variable `x` does not outlive
|
||||
bar(|| { //~ ERROR cannot infer an appropriate lifetime
|
||||
let _ = x;
|
||||
//~^ ERROR captured variable `x` does not outlive
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -14,5 +14,5 @@ fn new<T>() -> &'static T {
|
|||
|
||||
fn main() {
|
||||
let &v = new();
|
||||
//~^ ERROR cannot determine a type for this local variable: unconstrained type
|
||||
//~^ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -14,5 +14,5 @@ fn new<'r, T>() -> &'r T {
|
|||
|
||||
fn main() {
|
||||
let &v = new();
|
||||
//~^ ERROR cannot determine a type for this local variable: unconstrained type
|
||||
//~^ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -15,8 +15,5 @@ fn main() {
|
|||
let y: Gc<int> = box (GC) 0;
|
||||
|
||||
println!("{}", x + 1); //~ ERROR binary operation `+` cannot be applied to type `Box<int>`
|
||||
//~^ ERROR unable to infer enough type information
|
||||
println!("{}", y + 1);
|
||||
//~^ ERROR binary operation `+` cannot be applied to type `Gc<int>`
|
||||
//~^^ ERROR unable to infer enough type information
|
||||
println!("{}", y + 1); //~ ERROR binary operation `+` cannot be applied to type `Gc<int>`
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@
|
|||
|
||||
extern crate debug;
|
||||
|
||||
fn main() { format!("{:?}", None); } //~ ERROR unconstrained type
|
||||
fn main() { format!("{:?}", None); }
|
||||
//~^ ERROR type annotations required
|
||||
|
|
|
@ -9,4 +9,5 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn foo<T>(t: T) {}
|
||||
fn main() { foo(fail!()) } //~ ERROR cannot determine a type for this expression: unconstrained type
|
||||
fn main() { foo(fail!()) }
|
||||
//~^ ERROR type annotations required
|
||||
|
|
|
@ -12,5 +12,6 @@ extern crate debug;
|
|||
|
||||
fn main() {
|
||||
// Unconstrained type:
|
||||
format!("{:?}", None); //~ ERROR: E0101
|
||||
format!("{:?}", None);
|
||||
//~^ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -11,5 +11,6 @@
|
|||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
mem::transmute(0); //~ ERROR: cannot determine a type for this expression: unconstrained type
|
||||
mem::transmute(0);
|
||||
//~^ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
fn foo(b: bool) -> Result<bool,String> {
|
||||
Err("bar".to_string());
|
||||
//~^ ERROR: cannot determine a type for this expression: unconstrained type
|
||||
//~^ ERROR type annotations required
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -14,7 +14,7 @@ pub struct MyState;
|
|||
pub fn foo<State>(_: TypeWithState<State>) {}
|
||||
|
||||
pub fn bar() {
|
||||
foo(TypeWithState); //~ ERROR: cannot determine a type for this expression: unconstrained type
|
||||
foo(TypeWithState); //~ ERROR type annotations required
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let v = &[]; //~ ERROR cannot determine a type for this local variable: unconstrained type
|
||||
let it = v.iter();
|
||||
let v = &[];
|
||||
let it = v.iter(); //~ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -16,7 +16,27 @@ struct Foo {
|
|||
}
|
||||
|
||||
impl Drop for Foo {
|
||||
//~^ ERROR cannot implement a destructor on a structure or enumeration that does not satisfy Send
|
||||
//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo`
|
||||
//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send
|
||||
fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
struct Bar<'a> {
|
||||
f: &'a int,
|
||||
}
|
||||
|
||||
impl<'a> Drop for Bar<'a> {
|
||||
//~^ ERROR E0141
|
||||
fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
struct Baz {
|
||||
f: &'static int,
|
||||
}
|
||||
|
||||
impl Drop for Baz {
|
||||
fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ fn foo(_x: Gc<uint>) {}
|
|||
|
||||
fn main() {
|
||||
let x = box(GC) 3u;
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||
let _: proc() = proc() foo(x);
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@ trait Dummy { }
|
|||
|
||||
// careful with object types, who knows what they close over...
|
||||
fn test51<'a>() {
|
||||
assert_send::<&'a Dummy>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<&'a Dummy>();
|
||||
//~^ ERROR the trait `core::kinds::Send` is not implemented
|
||||
}
|
||||
fn test52<'a>() {
|
||||
assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<&'a Dummy+Send>();
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// ...unless they are properly bounded
|
||||
|
@ -35,12 +36,12 @@ fn test61() {
|
|||
// closure and object types can have lifetime bounds which make
|
||||
// them not ok
|
||||
fn test_70<'a>() {
|
||||
assert_send::<proc():'a>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<proc():'a>();
|
||||
//~^ ERROR the trait `core::kinds::Send` is not implemented
|
||||
}
|
||||
|
||||
fn test_71<'a>() {
|
||||
assert_send::<Box<Dummy+'a>>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<Box<Dummy+'a>>();
|
||||
//~^ ERROR the trait `core::kinds::Send` is not implemented
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ fn main() {
|
|||
|
||||
task::spawn(proc() {
|
||||
let y = x;
|
||||
//~^ ERROR does not fulfill `Send`
|
||||
//~^ ERROR `core::kinds::Send` is not implemented
|
||||
println!("{:?}", y);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,21 +57,22 @@ fn box_with_region_not_ok<'a>() {
|
|||
// objects with insufficient bounds no ok
|
||||
|
||||
fn object_with_random_bound_not_ok<'a>() {
|
||||
assert_send::<&'a Dummy+'a>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a Dummy+'a>();
|
||||
//~^ ERROR not implemented
|
||||
}
|
||||
|
||||
fn object_with_send_bound_not_ok<'a>() {
|
||||
assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a Dummy+Send>();
|
||||
//~^ ERROR does not fulfill
|
||||
}
|
||||
|
||||
fn proc_with_lifetime_not_ok<'a>() {
|
||||
assert_send::<proc():'a>(); //~ ERROR does not fulfill
|
||||
assert_send::<proc():'a>();
|
||||
//~^ ERROR not implemented
|
||||
}
|
||||
|
||||
fn closure_with_lifetime_not_ok<'a>() {
|
||||
assert_send::<||:'a>(); //~ ERROR does not fulfill
|
||||
assert_send::<||:'a>();
|
||||
//~^ ERROR not implemented
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
// Various examples of structs whose fields are not well-formed.
|
||||
|
||||
#![no_std]
|
||||
#![allow(dead_code)]
|
||||
|
||||
enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
// Issue #5062
|
||||
|
||||
fn main() {
|
||||
None; //~ ERROR cannot determine a type for this expression: unconstrained type
|
||||
None; //~ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -13,5 +13,5 @@ struct S<'a, T:'a> {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
S { o: &None }; //~ ERROR cannot determine a type for this expression: unconstrained type
|
||||
S { o: &None }; //~ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -12,25 +12,25 @@
|
|||
// Test `Sized?` types not allowed in fields (except the last one).
|
||||
|
||||
struct S1<Sized? X> {
|
||||
f1: X, //~ ERROR type `f1` is dynamically sized. dynamically sized types may only appear as the
|
||||
f1: X, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
f2: int,
|
||||
}
|
||||
struct S2<Sized? X> {
|
||||
f: int,
|
||||
g: X, //~ ERROR type `g` is dynamically sized. dynamically sized types may only appear as the ty
|
||||
g: X, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
h: int,
|
||||
}
|
||||
struct S3 {
|
||||
f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear
|
||||
f: str, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
g: [uint]
|
||||
}
|
||||
struct S4 {
|
||||
f: str, //~ ERROR type `f` is dynamically sized. dynamically sized types may only appear
|
||||
f: str, //~ ERROR `core::kinds::Sized` is not implemented
|
||||
g: uint
|
||||
}
|
||||
enum E<Sized? X> {
|
||||
V1(X, int), //~ERROR type `X` is dynamically sized. dynamically sized types may only appear as t
|
||||
V2{f1: X, f: int}, //~ERROR type `f1` is dynamically sized. dynamically sized types may only app
|
||||
V1(X, int), //~ERROR `core::kinds::Sized` is not implemented
|
||||
V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
|
||||
|
||||
fn main() {
|
||||
let _foo = Vec::new(); //~ ERROR unconstrained type
|
||||
let _foo = Vec::new(); //~ ERROR type annotations required
|
||||
}
|
||||
|
|
|
@ -19,3 +19,4 @@ pub extern fn bar() {}
|
|||
|
||||
#[lang = "stack_exhausted"] fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] fn eh_personality() {}
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
|
|
|
@ -19,3 +19,4 @@ pub extern fn foo() {}
|
|||
|
||||
#[lang = "stack_exhausted"] fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] fn eh_personality() {}
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
|
|||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "sized"] pub trait Sized {}
|
||||
#[lang = "fail_fmt"] fn fail_fmt() -> ! { loop {} }
|
||||
|
||||
#[start]
|
||||
#[no_split_stack]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue