mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-07 12:33:14 +00:00
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:
parent
c594959cdf
commit
53ece71585
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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 => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
@ -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 ());
|
||||
}
|
||||
|
@ -10,6 +10,5 @@
|
||||
|
||||
fn main() {
|
||||
println!("{}", std::mem::size_of_val(&1));
|
||||
//~^ ERROR cannot determine a type for this expression
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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];
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user