From 53ece7158500e561c69d6e07160518f19d8beafd Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Mon, 15 Dec 2014 09:45:28 -0500 Subject: [PATCH] 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 --- src/librustc/middle/infer/mod.rs | 21 ++++++++++- src/librustc/middle/ty.rs | 8 +++++ src/librustc_typeck/check/mod.rs | 19 ++++++++-- src/librustc_typeck/check/vtable.rs | 3 ++ src/test/compile-fail/issue-16966.rs | 3 +- ...traits-multidispatch-convert-ambig-dest.rs | 2 +- .../issue-6458-1.rs | 3 +- .../integer-literal-suffix-inference-2.rs | 2 +- .../integer-literal-suffix-inference-3.rs | 1 - .../{compile-fail => run-pass}/issue-11382.rs | 5 +-- .../{compile-fail => run-pass}/issue-15730.rs | 1 - .../{compile-fail => run-pass}/issue-16783.rs | 1 - ...ispatch-infer-convert-source-and-target.rs | 35 ------------------- ...aits-multidispatch-infer-convert-target.rs | 7 ++-- 14 files changed, 57 insertions(+), 54 deletions(-) rename src/test/{compile-fail => run-fail}/issue-6458-1.rs (92%) rename src/test/{compile-fail => run-pass}/integer-literal-suffix-inference-2.rs (88%) rename src/test/{compile-fail => run-pass}/integer-literal-suffix-inference-3.rs (89%) rename src/test/{compile-fail => run-pass}/issue-11382.rs (80%) rename src/test/{compile-fail => run-pass}/issue-15730.rs (85%) rename src/test/{compile-fail => run-pass}/issue-16783.rs (84%) delete mode 100644 src/test/run-pass/traits-multidispatch-infer-convert-source-and-target.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 91fbaca26d11..d9b7e04bc794 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -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, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8e7470f5084b..82a8bc3cd06c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2e3552047b48..1b45cc2f0d28 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 => { } + } } } } diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 15e942006f01..c85b542b6cae 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -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, diff --git a/src/test/compile-fail/issue-16966.rs b/src/test/compile-fail/issue-16966.rs index dfa23c48afa6..5dbf7546de22 100644 --- a/src/test/compile-fail/issue-16966.rs +++ b/src/test/compile-fail/issue-16966.rs @@ -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() ); } diff --git a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs index 3c461fd5b4b7..0a5aa1b7bd34 100644 --- a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs +++ b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs @@ -33,7 +33,7 @@ where T : Convert } fn a() { - test(22_i32, 44); //~ ERROR type annotations required + test(22_i32, std::default::Default::default()); //~ ERROR type annotations required } fn main() {} diff --git a/src/test/compile-fail/issue-6458-1.rs b/src/test/run-fail/issue-6458-1.rs similarity index 92% rename from src/test/compile-fail/issue-6458-1.rs rename to src/test/run-fail/issue-6458-1.rs index 52a57fa2f441..631517f6a3ca 100644 --- a/src/test/compile-fail/issue-6458-1.rs +++ b/src/test/run-fail/issue-6458-1.rs @@ -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) {} fn main() { foo(panic!()) } - //~^ ERROR type annotations required diff --git a/src/test/compile-fail/integer-literal-suffix-inference-2.rs b/src/test/run-pass/integer-literal-suffix-inference-2.rs similarity index 88% rename from src/test/compile-fail/integer-literal-suffix-inference-2.rs rename to src/test/run-pass/integer-literal-suffix-inference-2.rs index 7c862d04d206..05973a545a20 100644 --- a/src/test/compile-fail/integer-literal-suffix-inference-2.rs +++ b/src/test/run-pass/integer-literal-suffix-inference-2.rs @@ -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 ()); } diff --git a/src/test/compile-fail/integer-literal-suffix-inference-3.rs b/src/test/run-pass/integer-literal-suffix-inference-3.rs similarity index 89% rename from src/test/compile-fail/integer-literal-suffix-inference-3.rs rename to src/test/run-pass/integer-literal-suffix-inference-3.rs index dc3db9856603..05b275a0d8ca 100644 --- a/src/test/compile-fail/integer-literal-suffix-inference-3.rs +++ b/src/test/run-pass/integer-literal-suffix-inference-3.rs @@ -10,6 +10,5 @@ fn main() { println!("{}", std::mem::size_of_val(&1)); - //~^ ERROR cannot determine a type for this expression } diff --git a/src/test/compile-fail/issue-11382.rs b/src/test/run-pass/issue-11382.rs similarity index 80% rename from src/test/compile-fail/issue-11382.rs rename to src/test/run-pass/issue-11382.rs index 44f6cd7719d1..51996614d259 100644 --- a/src/test/compile-fail/issue-11382.rs +++ b/src/test/run-pass/issue-11382.rs @@ -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); } diff --git a/src/test/compile-fail/issue-15730.rs b/src/test/run-pass/issue-15730.rs similarity index 85% rename from src/test/compile-fail/issue-15730.rs rename to src/test/run-pass/issue-15730.rs index c29e74af03cd..a1a5922e1500 100644 --- a/src/test/compile-fail/issue-15730.rs +++ b/src/test/run-pass/issue-15730.rs @@ -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]; } diff --git a/src/test/compile-fail/issue-16783.rs b/src/test/run-pass/issue-16783.rs similarity index 84% rename from src/test/compile-fail/issue-16783.rs rename to src/test/run-pass/issue-16783.rs index 1b52bd9c3de9..cb12d138a5f2 100644 --- a/src/test/compile-fail/issue-16783.rs +++ b/src/test/run-pass/issue-16783.rs @@ -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(); } diff --git a/src/test/run-pass/traits-multidispatch-infer-convert-source-and-target.rs b/src/test/run-pass/traits-multidispatch-infer-convert-source-and-target.rs deleted file mode 100644 index c10029791df5..000000000000 --- a/src/test/run-pass/traits-multidispatch-infer-convert-source-and-target.rs +++ /dev/null @@ -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 or the MIT license -// , 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 { - fn convert(&self) -> Target; -} - -impl Convert for i16 { - fn convert(&self) -> u32 { - *self as u32 - } -} - -fn test(_: T, _: U, t_size: uint, u_size: uint) -where T : Convert -{ - assert_eq!(mem::size_of::(), t_size); - assert_eq!(mem::size_of::(), u_size); -} - -fn main() { - // T = i16, U = u32 - test(22, 44, 2, 4); -} diff --git a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs index 54515f3b0d7d..532ef7cbec6f 100644 --- a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs +++ b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs @@ -36,11 +36,10 @@ where T : Convert } 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); }