Skip to content

Commit 87f39e9

Browse files
committed
rustc_typeck: don't expect rvalues to have unsized types.
1 parent 34d6800 commit 87f39e9

File tree

4 files changed

+112
-61
lines changed

4 files changed

+112
-61
lines changed

src/librustc/middle/ty.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -4177,10 +4177,14 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
41774177
}
41784178

41794179
def::DefStruct(_) => {
4180-
match expr_ty(tcx, expr).sty {
4181-
ty_bare_fn(..) => RvalueDatumExpr,
4182-
_ => RvalueDpsExpr
4183-
}
4180+
match tcx.node_types.borrow().get(&expr.id) {
4181+
Some(ty) => match ty.sty {
4182+
ty_bare_fn(..) => RvalueDatumExpr,
4183+
_ => RvalueDpsExpr
4184+
},
4185+
// See ExprCast below for why types might be missing.
4186+
None => RvalueDatumExpr
4187+
}
41844188
}
41854189

41864190
// Special case: A unit like struct's constructor must be called without () at the

src/librustc_typeck/check/closure.rs

+18-40
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010

1111
//! Code for type-checking closure expressions.
1212
13-
use super::check_fn;
14-
use super::{Expectation, ExpectCastableToType, ExpectHasType, NoExpectation};
15-
use super::FnCtxt;
13+
use super::{check_fn, Expectation, FnCtxt};
1614

1715
use astconv;
1816
use middle::infer;
1917
use middle::subst;
20-
use middle::ty::{mod, Ty};
18+
use middle::ty;
2119
use rscope::RegionScope;
2220
use syntax::abi;
2321
use syntax::ast;
@@ -34,13 +32,27 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
3432
expr.repr(fcx.tcx()),
3533
expected.repr(fcx.tcx()));
3634

35+
let expected_sig_and_kind = expected.map_to_option(fcx, |ty| {
36+
match ty.sty {
37+
ty::ty_trait(ref object_type) => {
38+
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
39+
}
40+
ty::ty_infer(ty::TyVar(vid)) => {
41+
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
42+
}
43+
_ => {
44+
None
45+
}
46+
}
47+
});
48+
3749
match opt_kind {
3850
None => {
3951
// If users didn't specify what sort of closure they want,
4052
// examine the expected type. For now, if we see explicit
4153
// evidence than an unboxed closure is desired, we'll use
4254
// that, otherwise we'll fall back to boxed closures.
43-
match deduce_unboxed_closure_expectations_from_expectation(fcx, expected) {
55+
match expected_sig_and_kind {
4456
None => { // doesn't look like an unboxed closure
4557
let region = astconv::opt_ast_region_to_region(fcx,
4658
fcx.infcx(),
@@ -66,10 +78,7 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
6678
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
6779
};
6880

69-
let expected_sig =
70-
deduce_unboxed_closure_expectations_from_expectation(fcx, expected)
71-
.map(|t| t.0);
72-
81+
let expected_sig = expected_sig_and_kind.map(|t| t.0);
7382
check_unboxed_closure(fcx, expr, kind, decl, body, expected_sig);
7483
}
7584
}
@@ -147,37 +156,6 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
147156
.insert(expr_def_id, unboxed_closure);
148157
}
149158

150-
fn deduce_unboxed_closure_expectations_from_expectation<'a,'tcx>(
151-
fcx: &FnCtxt<'a,'tcx>,
152-
expected: Expectation<'tcx>)
153-
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
154-
{
155-
match expected.resolve(fcx) {
156-
NoExpectation => None,
157-
ExpectCastableToType(t) | ExpectHasType(t) => {
158-
deduce_unboxed_closure_expectations_from_expected_type(fcx, t)
159-
}
160-
}
161-
}
162-
163-
fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
164-
fcx: &FnCtxt<'a,'tcx>,
165-
expected_ty: Ty<'tcx>)
166-
-> Option<(ty::FnSig<'tcx>,ty::UnboxedClosureKind)>
167-
{
168-
match expected_ty.sty {
169-
ty::ty_trait(ref object_type) => {
170-
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
171-
}
172-
ty::ty_infer(ty::TyVar(vid)) => {
173-
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
174-
}
175-
_ => {
176-
None
177-
}
178-
}
179-
}
180-
181159
fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
182160
fcx: &FnCtxt<'a,'tcx>,
183161
trait_ref: &ty::PolyTraitRef<'tcx>)

src/librustc_typeck/check/mod.rs

+56-17
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ enum Expectation<'tcx> {
176176

177177
/// This expression will be cast to the `Ty`
178178
ExpectCastableToType(Ty<'tcx>),
179+
180+
/// This rvalue expression will be wrapped in `&` or `Box` and coerced
181+
/// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
182+
ExpectRvalueLikeUnsized(Ty<'tcx>),
179183
}
180184

181185
impl<'tcx> Expectation<'tcx> {
@@ -196,7 +200,7 @@ impl<'tcx> Expectation<'tcx> {
196200
// when checking the 'then' block which are incompatible with the
197201
// 'else' branch.
198202
fn adjust_for_branches<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
199-
match self.only_has_type() {
203+
match *self {
200204
ExpectHasType(ety) => {
201205
let ety = fcx.infcx().shallow_resolve(ety);
202206
if !ty::type_is_ty_var(ety) {
@@ -205,6 +209,9 @@ impl<'tcx> Expectation<'tcx> {
205209
NoExpectation
206210
}
207211
}
212+
ExpectRvalueLikeUnsized(ety) => {
213+
ExpectRvalueLikeUnsized(ety)
214+
}
208215
_ => NoExpectation
209216
}
210217
}
@@ -3658,7 +3665,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
36583665
match unop {
36593666
ast::UnUniq => match ty.sty {
36603667
ty::ty_uniq(ty) => {
3661-
ExpectHasType(ty)
3668+
Expectation::rvalue_hint(ty)
36623669
}
36633670
_ => {
36643671
NoExpectation
@@ -3747,7 +3754,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
37473754
let expected = expected.only_has_type();
37483755
let hint = expected.map(fcx, |ty| {
37493756
match ty.sty {
3750-
ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => ExpectHasType(mt.ty),
3757+
ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => {
3758+
if ty::expr_is_lval(fcx.tcx(), &**oprnd) {
3759+
ExpectHasType(mt.ty)
3760+
} else {
3761+
Expectation::rvalue_hint(mt.ty)
3762+
}
3763+
}
37513764
_ => NoExpectation
37523765
}
37533766
});
@@ -3965,15 +3978,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
39653978
check_cast(fcx, expr, &**e, &**t);
39663979
}
39673980
ast::ExprVec(ref args) => {
3968-
let uty = match expected {
3969-
ExpectHasType(uty) => {
3970-
match uty.sty {
3971-
ty::ty_vec(ty, _) => Some(ty),
3972-
_ => None
3973-
}
3981+
let uty = expected.map_to_option(fcx, |uty| {
3982+
match uty.sty {
3983+
ty::ty_vec(ty, _) => Some(ty),
3984+
_ => None
39743985
}
3975-
_ => None
3976-
};
3986+
});
39773987

39783988
let typ = match uty {
39793989
Some(uty) => {
@@ -4000,8 +4010,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
40004010
let uty = match expected {
40014011
ExpectHasType(uty) => {
40024012
match uty.sty {
4003-
ty::ty_vec(ty, _) => Some(ty),
4004-
_ => None
4013+
ty::ty_vec(ty, _) => Some(ty),
4014+
_ => None
40054015
}
40064016
}
40074017
_ => None
@@ -4278,10 +4288,29 @@ fn constrain_path_type_parameters(fcx: &FnCtxt,
42784288
}
42794289

42804290
impl<'tcx> Expectation<'tcx> {
4291+
/// Provide an expectation for an rvalue expression given an *optional*
4292+
/// hint, which is not required for type safety (the resulting type might
4293+
/// be checked higher up, as is the case with `&expr` and `box expr`), but
4294+
/// is useful in determining the concrete type.
4295+
///
4296+
/// The primary usecase is unpacking `&T` and `Box<T>`, where `T` is
4297+
/// unsized and propagating `ExpectHasType(T)` would try to assign `T` to
4298+
/// an rvalue expression, which is invalid. Instead, a weaker hint is used.
4299+
/// This is required, when e.g `T` is `[u8]` and the rvalue is `[1, 2, 3]`,
4300+
/// without the hint the integer literals would remain uninferred.
4301+
fn rvalue_hint(ty: Ty<'tcx>) -> Expectation<'tcx> {
4302+
match ty.sty {
4303+
ty::ty_vec(_, None) | ty::ty_trait(..) => {
4304+
ExpectRvalueLikeUnsized(ty)
4305+
}
4306+
_ => ExpectHasType(ty)
4307+
}
4308+
}
4309+
42814310
fn only_has_type(self) -> Expectation<'tcx> {
42824311
match self {
4283-
NoExpectation | ExpectCastableToType(..) => NoExpectation,
4284-
ExpectHasType(t) => ExpectHasType(t)
4312+
ExpectHasType(t) => ExpectHasType(t),
4313+
_ => NoExpectation
42854314
}
42864315
}
42874316

@@ -4301,6 +4330,10 @@ impl<'tcx> Expectation<'tcx> {
43014330
ExpectHasType(
43024331
fcx.infcx().resolve_type_vars_if_possible(&t))
43034332
}
4333+
ExpectRvalueLikeUnsized(t) => {
4334+
ExpectRvalueLikeUnsized(
4335+
fcx.infcx().resolve_type_vars_if_possible(&t))
4336+
}
43044337
}
43054338
}
43064339

@@ -4309,7 +4342,9 @@ impl<'tcx> Expectation<'tcx> {
43094342
{
43104343
match self.resolve(fcx) {
43114344
NoExpectation => NoExpectation,
4312-
ExpectCastableToType(ty) | ExpectHasType(ty) => unpack(ty),
4345+
ExpectCastableToType(ty) |
4346+
ExpectHasType(ty) |
4347+
ExpectRvalueLikeUnsized(ty) => unpack(ty),
43134348
}
43144349
}
43154350

@@ -4318,7 +4353,9 @@ impl<'tcx> Expectation<'tcx> {
43184353
{
43194354
match self.resolve(fcx) {
43204355
NoExpectation => None,
4321-
ExpectCastableToType(ty) | ExpectHasType(ty) => unpack(ty),
4356+
ExpectCastableToType(ty) |
4357+
ExpectHasType(ty) |
4358+
ExpectRvalueLikeUnsized(ty) => unpack(ty),
43224359
}
43234360
}
43244361
}
@@ -4331,6 +4368,8 @@ impl<'tcx> Repr<'tcx> for Expectation<'tcx> {
43314368
t.repr(tcx)),
43324369
ExpectCastableToType(t) => format!("ExpectCastableToType({})",
43334370
t.repr(tcx)),
4371+
ExpectRvalueLikeUnsized(t) => format!("ExpectRvalueLikeUnsized({})",
4372+
t.repr(tcx)),
43344373
}
43354374
}
43364375
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::fmt::Show;
12+
13+
// Check that coercions apply at the pointer level and don't cause
14+
// rvalue expressions to be unsized.
15+
16+
pub fn main() {
17+
let _: Box<[int]> = box { [1, 2, 3] };
18+
let _: Box<[int]> = box if true { [1, 2, 3] } else { [1, 3, 4] };
19+
let _: Box<[int]> = box match true { true => [1, 2, 3], false => [1, 3, 4] };
20+
let _: Box<Fn(int) -> _> = box { |x| (x as u8) };
21+
let _: Box<Show> = box if true { false } else { true };
22+
let _: Box<Show> = box match true { true => 'a', false => 'b' };
23+
24+
let _: &[int] = &{ [1, 2, 3] };
25+
let _: &[int] = &if true { [1, 2, 3] } else { [1, 3, 4] };
26+
let _: &[int] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
27+
let _: &Fn(int) -> _ = &{ |x| (x as u8) };
28+
let _: &Show = &if true { false } else { true };
29+
let _: &Show = &match true { true => 'a', false => 'b' };
30+
}

0 commit comments

Comments
 (0)