Implement numeric fallback

Doesn't yet converge on a fixed point, but generally works. A better algorithm
will come with the implementation of default type parameter fallback.

If inference fails to determine an exact integral or floating point type, it
will set the type to i32 or f64, respectively.

Closes #16968
This commit is contained in:
Corey Richardson 2014-12-15 09:45:28 -05:00
parent c594959cdf
commit 53ece71585
14 changed files with 57 additions and 54 deletions

View File

@ -23,7 +23,7 @@ pub use self::freshen::TypeFreshener;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
use middle::ty::replace_late_bound_regions;
use middle::ty::{mod, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable};
@ -525,6 +525,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
freshen::TypeFreshener::new(self)
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
ty::ty_infer(ty::IntVar(vid)) => {
match self.int_unification_table.borrow_mut().get(self.tcx, vid).value {
None => UnconstrainedInt,
_ => Neither,
}
},
ty::ty_infer(ty::FloatVar(vid)) => {
match self.float_unification_table.borrow_mut().get(self.tcx, vid).value {
None => return UnconstrainedFloat,
_ => Neither,
}
},
_ => Neither,
}
}
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'b, 'tcx> {
CombineFields {infcx: self,

View File

@ -1641,6 +1641,14 @@ pub enum InferTy {
FreshIntTy(u32),
}
#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Show, Copy)]
pub enum UnconstrainedNumeric {
UnconstrainedFloat,
UnconstrainedInt,
Neither,
}
#[deriving(Clone, RustcEncodable, RustcDecodable, Eq, Hash, Show, Copy)]
pub enum InferRegion {
ReVar(RegionVid),

View File

@ -453,7 +453,6 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vtable::select_all_fcx_obligations_or_error(&fcx);
regionck::regionck_fn(&fcx, id, decl, body);
fcx.default_diverging_type_variables_to_nil();
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
}
_ => ccx.tcx.sess.impossible_case(body.span,
@ -1666,10 +1665,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
pub fn default_diverging_type_variables_to_nil(&self) {
/// Apply "fallbacks" to some types
/// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
pub fn default_type_parameters(&self) {
use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) {
let resolved = self.infcx().resolve_type_vars_if_possible(ty);
if self.infcx().type_var_diverges(resolved) {
demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx()));
} else {
match self.infcx().type_is_unconstrained_numeric(resolved) {
UnconstrainedInt => {
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
},
UnconstrainedFloat => {
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
}
Neither => { }
}
}
}
}

View File

@ -407,6 +407,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
debug!("select_all_fcx_obligations_or_error");
select_fcx_obligations_where_possible(fcx);
fcx.default_type_parameters();
let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
&fcx.inh.param_env,

View File

@ -8,8 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:type annotations required
fn main() {
panic!(
1.2 //~ ERROR cannot determine a type for this expression
std::default::Default::default()
);
}

View File

@ -33,7 +33,7 @@ where T : Convert<U>
}
fn a() {
test(22_i32, 44); //~ ERROR type annotations required
test(22_i32, std::default::Default::default()); //~ ERROR type annotations required
}
fn main() {}

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:explicit panic
fn foo<T>(t: T) {}
fn main() { foo(panic!()) }
//~^ ERROR type annotations required

View File

@ -11,7 +11,7 @@
fn foo(_: *const ()) {}
fn main() {
let a = 3; //~ ERROR cannot determine a type for this local variable
let a = 3;
foo(&a as *const _ as *const ());
}

View File

@ -10,6 +10,5 @@
fn main() {
println!("{}", std::mem::size_of_val(&1));
//~^ ERROR cannot determine a type for this expression
}

View File

@ -9,8 +9,5 @@
// except according to those terms.
fn main() {
panic!(
1.2
//~^ ERROR cannot determine the type of this number; add a suffix to specify the type explicitly
);
println!("{}", 1.2);
}

View File

@ -12,6 +12,5 @@
fn main() {
let mut array = [1, 2, 3];
//~^ ERROR cannot determine a type for this local variable: cannot determine the type of this integ
let pie_slice = array[1..2];
}

View File

@ -10,6 +10,5 @@
pub fn main() {
let x = [1, 2, 3];
//~^ ERROR cannot determine a type for this local variable: cannot determine the type of this
let y = x.as_slice();
}

View File

@ -1,35 +0,0 @@
// 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.
// Test that if there is one impl we can infer everything.
use std::mem;
trait Convert<Target> {
fn convert(&self) -> Target;
}
impl Convert<u32> for i16 {
fn convert(&self) -> u32 {
*self as u32
}
}
fn test<T,U>(_: T, _: U, t_size: uint, u_size: uint)
where T : Convert<U>
{
assert_eq!(mem::size_of::<T>(), t_size);
assert_eq!(mem::size_of::<U>(), u_size);
}
fn main() {
// T = i16, U = u32
test(22, 44, 2, 4);
}

View File

@ -36,11 +36,10 @@ where T : Convert<U>
}
fn main() {
use std::default::Default;
// T = i16, U = u32
test(22_i16, 44, 2, 4);
test(22, 44_u32, 2, 4);
test(22_i16, Default::default(), 2, 4);
// T = u32, U = i16
test(22_u32, 44, 4, 2);
test(22, 44_i16, 4, 2);
test(22_u32, Default::default(), 4, 2);
}