Skip to content

Commit

Permalink
Make bottom type fallback lazy
Browse files Browse the repository at this point in the history
PR rust-lang#17603 introduced bottom type fallback but did it a bit too
eagerly. This patch makes the fallback lazy so that `typeck` can run
its cause and detect as many type errors as possible with regard to
diverging types.

Closes rust-lang#21878
  • Loading branch information
edwardw committed Feb 6, 2015
1 parent f3573aa commit 943f62c
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 17 deletions.
9 changes: 7 additions & 2 deletions src/librustc/middle/infer/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
let t = self.infcx.shallow_resolve(t);
match t.sty {
ty::ty_infer(ty::TyVar(vid)) => {
self.err = Some(unresolved_ty(vid));
self.tcx().types.err
if self.infcx.type_var_diverges(t) {
// Apply type fallbacks: ! gets replaced with ()
ty::mk_nil(self.tcx())
} else {
self.err = Some(unresolved_ty(vid));
self.tcx().types.err
}
}
ty::ty_infer(ty::IntVar(vid)) => {
self.err = Some(unresolved_int_ty(vid));
Expand Down
20 changes: 8 additions & 12 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1338,23 +1338,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

/// Apply "fallbacks" to some types
/// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
/// Unconstrained ints gets replaced with i32, and unconstrained floats with f64.
pub fn default_type_parameters(&self) {
use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
for (_, &mut ref ty) in &mut *self.inh.node_types.borrow_mut() {
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 => { }
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 => { }
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/test/compile-fail/bot-ambig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2015 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.

// Make sure that bottom type fallback doesn't introduce type system
// holes. See issue #21878 for more details.

trait Foo {}
impl Foo for () {}
impl Foo for i32 {}

struct Error;
impl Error {
fn foo(&self) -> ! { loop {} }
}

fn bar<T: Foo>() -> Result<T, Error> { loop {} }

fn main() {
let _ = bar().unwrap_or_else(|e| e.foo()); //~ ERROR unable to infer enough type information
}
28 changes: 28 additions & 0 deletions src/test/compile-fail/bot-wrong-annotation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2015 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.

// Make sure that bottom type fallback doesn't introduce type system
// holes. See issue #21878 for more details.

trait Foo {}
impl Foo for () {}
impl Foo for i32 {}

struct Error;
impl Error {
fn foo(&self) -> ! { loop {} }
}

fn bar<T: Foo>() -> Result<T, Error> { loop {} }

fn main() {
let _: u8 = bar().unwrap_or_else(|e| e.foo());
//~^ ERROR the trait `Foo` is not implemented for the type `u8`
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@
// 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!()) }
fn main() { foo(panic!()) } //~ ERROR unable to infer enough type information
29 changes: 29 additions & 0 deletions src/test/run-fail/bot-annotated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2015 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.

// Make sure that bottom type fallback doesn't introduce type system
// holes. See issue #21878 for more details.

// error-pattern:explicit panic

trait Foo {}
impl Foo for () {}
impl Foo for i32 {}

struct Error;
impl Error {
fn foo(&self) -> ! { panic!() }
}

fn bar<T: Foo>() -> Result<T, Error> { panic!() }

fn main() {
let _: i32 = bar().unwrap_or_else(|e| e.foo());
}

0 comments on commit 943f62c

Please sign in to comment.