Skip to content

librustc: Allow coercions through arrays. #15069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ pub fn type_is_self(ty: t) -> bool {
}
}

fn type_is_slice(ty:t) -> bool {
fn type_is_slice(ty: t) -> bool {
match get(ty).sty {
ty_rptr(_, mt) => match get(mt.ty).sty {
ty_vec(_, None) | ty_str => true,
Expand All @@ -1543,6 +1543,18 @@ fn type_is_slice(ty:t) -> bool {
}
}

pub fn type_is_vec(ty: t) -> bool {
match get(ty).sty {
ty_vec(..) => true,
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
ty_box(t) | ty_uniq(t) => match get(t).sty {
ty_vec(_, None) => true,
_ => false
},
_ => false
}
}

pub fn type_is_structural(ty: t) -> bool {
match get(ty).sty {
ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
Expand All @@ -1560,7 +1572,7 @@ pub fn type_is_simd(cx: &ctxt, ty: t) -> bool {

pub fn sequence_element_type(cx: &ctxt, ty: t) -> t {
match get(ty).sty {
ty_vec(mt, Some(_)) => mt.ty,
ty_vec(mt, _) => mt.ty,
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
ty_box(t) | ty_uniq(t) => match get(t).sty {
ty_vec(mt, None) => mt.ty,
Expand Down
51 changes: 27 additions & 24 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1146,24 +1146,9 @@ fn check_cast(fcx: &FnCtxt,
.span_err(span,
"cannot cast as `bool`, compare with zero instead");
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
fn is_vec(t: ty::t) -> bool {
match ty::get(t).sty {
ty::ty_vec(..) => true,
ty::ty_ptr(ty::mt{ty: t, ..}) |
ty::ty_rptr(_, ty::mt{ty: t, ..}) |
ty::ty_box(t) |
ty::ty_uniq(t) => {
match ty::get(t).sty {
ty::ty_vec(_, None) => true,
_ => false,
}
}
_ => false
}
}
fn types_compatible(fcx: &FnCtxt, sp: Span,
t1: ty::t, t2: ty::t) -> bool {
if !is_vec(t1) {
if !ty::type_is_vec(t1) {
// If the type being casted from is not a vector, this special
// case does not apply.
return false
Expand Down Expand Up @@ -2779,10 +2764,30 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.write_ty(id, enum_type);
}

type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, ty::t);

fn check_fn_for_vec_elements_expected(fcx: &FnCtxt,
expected: Expectation)
-> (ExprCheckerWithTy, ty::t) {
let tcx = fcx.ccx.tcx;
let (coerce, t) = match expected {
// If we're given an expected type, we can try to coerce to it
ExpectHasType(t) if ty::type_is_vec(t) => (true, ty::sequence_element_type(tcx, t)),
// Otherwise we just leave the type to be resolved later
_ => (false, fcx.infcx().next_ty_var())
};
if coerce {
(check_expr_coercable_to_type, t)
} else {
(check_expr_has_type, t)
}
}

let tcx = fcx.ccx.tcx;
let id = expr.id;
match expr.node {
ast::ExprVstore(ev, vst) => {
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
let typ = match ev.node {
ast::ExprVec(ref args) => {
let mutability = match vst {
Expand All @@ -2791,9 +2796,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
};
let mut any_error = false;
let mut any_bot = false;
let t: ty::t = fcx.infcx().next_ty_var();
for e in args.iter() {
check_expr_has_type(fcx, &**e, t);
check(fcx, &**e, t);
let arg_t = fcx.expr_ty(&**e);
if ty::type_is_error(arg_t) {
any_error = true;
Expand Down Expand Up @@ -2821,8 +2825,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
ast::ExprVstoreMutSlice => ast::MutMutable,
_ => ast::MutImmutable,
};
let t = fcx.infcx().next_ty_var();
check_expr_has_type(fcx, &**element, t);
check(fcx, &**element, t);
let arg_t = fcx.expr_ty(&**element);
if ty::type_is_error(arg_t) {
ty::mk_err()
Expand Down Expand Up @@ -3211,9 +3214,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
check_cast(fcx, &**e, &**t, id, expr.span);
}
ast::ExprVec(ref args) => {
let t: ty::t = fcx.infcx().next_ty_var();
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
for e in args.iter() {
check_expr_has_type(fcx, &**e, t);
check(fcx, &**e, t);
}
let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
Some(args.len()));
Expand All @@ -3222,8 +3225,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
ast::ExprRepeat(ref element, ref count_expr) => {
check_expr_has_type(fcx, &**count_expr, ty::mk_uint());
let count = ty::eval_repeat_count(fcx, &**count_expr);
let t: ty::t = fcx.infcx().next_ty_var();
check_expr_has_type(fcx, &**element, t);
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
check(fcx, &**element, t);
let element_ty = fcx.expr_ty(&**element);
if ty::type_is_error(element_ty) {
fcx.write_error(id);
Expand Down
92 changes: 92 additions & 0 deletions src/test/run-pass/issue-11205.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

trait Foo {}
impl Foo for int {}
fn foo(_: [&Foo, ..2]) {}
fn foos(_: &[&Foo]) {}
fn foog<T>(_: &[T], _: &[T]) {}

fn bar(_: [Box<Foo>, ..2]) {}
fn bars(_: &[Box<Foo>]) {}

fn main() {
let x: [&Foo, ..2] = [&1i, &2i];
foo(x);
foo([&1i, &2i]);

let r = &1i;
let x: [&Foo, ..2] = [r, ..2];
foo(x);
foo([&1i, ..2]);

let x: &[&Foo] = &[&1i, &2i];
foos(x);
foos(&[&1i, &2i]);

let x: &[&Foo] = &[&1i, &2i];
let r = &1i;
foog(x, &[r]);

let x: [Box<Foo>, ..2] = [box 1i, box 2i];
bar(x);
bar([box 1i, box 2i]);

let x: &[Box<Foo>] = &[box 1i, box 2i];
bars(x);
bars(&[box 1i, box 2i]);

let x: &[Box<Foo>] = &[box 1i, box 2i];
foog(x, &[box 1i]);

struct T<'a> {
t: [&'a Foo, ..2]
}
let _n = T {
t: [&1i, &2i]
};
let r = &1i;
let _n = T {
t: [r, ..2]
};
let x: [&Foo, ..2] = [&1i, &2i];
let _n = T {
t: x
};

struct F<'b> {
t: &'b [&'b Foo]
}
let _n = F {
t: &[&1i, &2i]
};
let r = &1i;
let r: [&Foo, ..2] = [r, ..2];
let _n = F {
t: r
};
let x: [&Foo, ..2] = [&1i, &2i];
let _n = F {
t: x
};

struct M<'a> {
t: &'a [Box<Foo>]
}
let _n = M {
t: &[box 1i, box 2i]
};
let x: [Box<Foo>, ..2] = [box 1i, box 2i];
let _n = M {
t: x
};
}