diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8d84d089c01..e983830a4c3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, @@ -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(_) | @@ -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, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index bb20c3ce0b4..54cd88a1163 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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 @@ -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 { @@ -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; @@ -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() @@ -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())); @@ -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); diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs new file mode 100644 index 00000000000..5b52bc34d2b --- /dev/null +++ b/src/test/run-pass/issue-11205.rs @@ -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 or the MIT license +// , 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]) {} + +fn bar(_: [Box, ..2]) {} +fn bars(_: &[Box]) {} + +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, ..2] = [box 1i, box 2i]; + bar(x); + bar([box 1i, box 2i]); + + let x: &[Box] = &[box 1i, box 2i]; + bars(x); + bars(&[box 1i, box 2i]); + + let x: &[Box] = &[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] + } + let _n = M { + t: &[box 1i, box 2i] + }; + let x: [Box, ..2] = [box 1i, box 2i]; + let _n = M { + t: x + }; +}